<commit_before>/*
   Copyright 2017 Thomas Krause <thomaskrause@posteo.de>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "jsonqueryparser.h"
#include <annis/annosearch/exactannokeysearch.h>    // for ExactAnnoKeySearch
#include <annis/annosearch/exactannovaluesearch.h>  // for ExactAnnoValueSearch
#include <annis/annosearch/regexannosearch.h>       // for RegexAnnoSearch
#include <annis/operators/dominance.h>              // for Dominance
#include <annis/operators/identicalcoverage.h>      // for IdenticalCoverage
#include <annis/operators/identicalnode.h>
#include <annis/operators/inclusion.h>              // for Inclusion
#include <annis/operators/overlap.h>                // for Overlap
#include <annis/operators/pointing.h>               // for Pointing
#include <annis/operators/precedence.h>             // for Precedence
#include <annis/operators/partofsubcorpus.h>
#include <assert.h>                                 // for assert
#include <re2/re2.h>                                // for RE2
#include <limits>                                   // for numeric_limits
#include <map>                                      // for _Rb_tree_const_it...
#include <utility>                                  // for pair
#include "annis/db.h"                               // for DB
#include "annis/json/json.h"                        // for Value, ValueConst...
#include "annis/query/query.h"                            // for Query
#include "annis/queryconfig.h"                      // for QueryConfig
#include "annis/stringstorage.h"                    // for StringStorage
#include "annis/types.h"                          // for Edge, GraphStatistic

#include <boost/optional.hpp>

#include <functional>

using namespace annis;

JSONQueryParser::JSONQueryParser()
{
}
std::shared_ptr<Query> JSONQueryParser::parse(DB &db, std::istream& jsonStream, const QueryConfig config)
{
  return parse(db, db.f_getGraphStorage, db.f_getAllGraphStorages, jsonStream, config);
}

std::shared_ptr<Query> JSONQueryParser::parse(const DB& db, DB::GetGSFuncT getGraphStorageFunc,
                                              DB::GetAllGSFuncT getAllGraphStorageFunc,
                                              std::istream& jsonStream, const QueryConfig config)
{
  std::vector<std::shared_ptr<SingleAlternativeQuery>> result;

  // parse root as value
  Json::Value root;
  jsonStream >> root;

  // iterate over all alternatives
  const auto& alternatives = root["alternatives"];
  for(const auto& alt : alternatives)
  {
    std::shared_ptr<SingleAlternativeQuery> q = std::make_shared<SingleAlternativeQuery>(db, config);

    // add all nodes
    const auto& nodes = alt["nodes"];

    std::map<std::uint64_t, size_t> nodeIdToPos;
    boost::optional<size_t> firstNodePos;
    for (auto it = nodes.begin(); it != nodes.end(); it++)
    {
      auto& n = *it;
      size_t pos = parseNode(db, n, getGraphStorageFunc, q);
      nodeIdToPos[std::stoull(it.name())] = pos;
      if(!firstNodePos)
      {
        firstNodePos = pos;
      }
    }

    // add all joins
    const auto& joins = alt["joins"];
    for (auto it = joins.begin(); it != joins.end(); it++)
    {
      parseJoin(db, getGraphStorageFunc, getAllGraphStorageFunc, *it, q, nodeIdToPos);
    }

    // add all meta-data
    const auto& meta = alt["meta"];
    boost::optional<size_t> firstMetaIdx = boost::none;
    for (auto it = meta.begin(); it != meta.end(); it++)
    {
      auto& m = *it;

      // add an artificial node that describes the document/corpus node
      size_t metaNodeIdx = addNodeAnnotation(db, q, optStr(m["namespace"]),
            optStr(m["name"]), optStr(m["value"]),
            optStr(m["textMatching"]));

      if(firstMetaIdx)
      {
        // avoid nested loops by joining additional meta nodes with a "identical node"
        q->addOperator(std::make_shared<IdenticalNode>(db), metaNodeIdx, *firstMetaIdx);

      }
      else
      {
        firstMetaIdx = metaNodeIdx;
        // add a special join to the first node of the query
        q->addOperator(std::make_shared<PartOfSubCorpus>(getGraphStorageFunc, db.strings),
          metaNodeIdx, *firstNodePos);

      }
    }

    result.push_back(q);

  } // end for each alternative
  return std::make_shared<Query>(result);
}

std::shared_ptr<Query> JSONQueryParser::parseWithUpgradeableLock(DB &db,
                                                                 std::string queryAsJSON, boost::upgrade_lock<DBLoader>& lock,
                                                                 const QueryConfig config)
{
  DB::GetAllGSFuncT allFunc = [&db,&lock](ComponentType type, const std::string &name)
  {
    if(db.allGraphStoragesLoaded(type, name))
    {
      return db.getAllGraphStorages(type, name);
    }
    else
    {
      // loading the graph storages needs a unique lock to ensure nobody else is loading the same GS at the same time
      boost::upgrade_to_unique_lock<DBLoader> uniqueLock(lock);
      return db.getAllGraphStorages(type, name);
    }
  };

  DB::GetGSFuncT func = [&db,&lock](ComponentType type, const std::string &layer, const std::string &name)
  {
    if(db.isGraphStorageLoaded(type, layer, name))
    {
      return db.getGraphStorage(type, layer, name);
    }
    else
    {
      // loading the graph storages needs a unique lock to ensure nobody else is loading the same GS at the same time
      boost::upgrade_to_unique_lock<DBLoader> uniqueLock(lock);
      return db.getGraphStorage(type, layer, name);
    }
  };

  std::stringstream ss;
  ss << queryAsJSON;
  return annis::JSONQueryParser::parse(db, func, allFunc, ss, config);
}

size_t JSONQueryParser::parseNode(const DB& db, const Json::Value node, DB::GetGSFuncT getGraphStorageFunc, std::shared_ptr<SingleAlternativeQuery> q)
{

  // annotation search?
  if (node["nodeAnnotations"].isArray() && node["nodeAnnotations"].size() > 0)
  {
    // get the first one
    auto nodeAnno = node["nodeAnnotations"][0];

    return addNodeAnnotation(db, q, optStr(nodeAnno["namespace"]),
      optStr(nodeAnno["name"]), optStr(nodeAnno["value"]),
      optStr(nodeAnno["textMatching"]));

  }// end if annotation search
  else
  {
    // check for special non-annotation search constructs
    // token search?
    if (node["spannedText"].isString()
      || (node["token"].isBool() && node["token"].asBool()))
    {
      size_t n_pos = addNodeAnnotation(db, q, optStr(annis_ns), optStr(annis_tok),
                                       optStr(node["spannedText"]),
                                       optStr(node["spanTextMatching"]), true);

      std::shared_ptr<const ReadableGraphStorage> covGS = getGraphStorageFunc(ComponentType::COVERAGE, annis_ns, "");
      if(covGS)
      {
        q->addFilter(n_pos, [&db, covGS] (const Match& m) -> bool
        {
          return static_cast<bool>(db.nodeAnnos.getAnnotations(m.node, db.getNamespaceStringID(), db.getTokStringID()))
              && covGS->getOutgoingEdges(m.node).empty();
        }, "is_token");
      }

      return n_pos;
    }// end if token has spanned text
    else
    {
      // just search for any node
      return addNodeAnnotation(db, q, optStr(annis_ns), optStr(annis_node_type),
        boost::optional<std::string>("node"), boost::optional<std::string>("EXACT_EQUAL"));
    }
  } // end if special case

}

size_t JSONQueryParser::addNodeAnnotation(const DB& db,
  std::shared_ptr<SingleAlternativeQuery> q,
  boost::optional<std::string> ns,
  boost::optional<std::string> name,
  boost::optional<std::string> value,
  boost::optional<std::string> textMatching,
  bool wrapEmptyAnno)
{

  if (value)
  {
    bool exact = *textMatching == "EXACT_EQUAL";
    bool regex = *textMatching == "REGEXP_EQUAL";
    if(regex)
    {
      if(canReplaceRegex(*value))
      {
        exact = true;
      }
    }

    // search for the value
    if (exact)
    {
      // has namespace?
      if (ns)
      {
        return q->addNode(std::make_shared<ExactAnnoValueSearch>(db,
          *ns,
          *name,
          *value),
          wrapEmptyAnno);
      }
      else
      {
        return q->addNode(std::make_shared<ExactAnnoValueSearch>(db,
          *name,
          *value),
          wrapEmptyAnno);
      }
    }
    else if (regex)
    {
      // has namespace?
      if (ns)
      {
        return q->addNode(std::make_shared<RegexAnnoSearch>(db,
          *ns,
          *name,
          *value),
          wrapEmptyAnno);
      }
      else
      {
        return q->addNode(std::make_shared<RegexAnnoSearch>(db,
          *name,
          *value),
          wrapEmptyAnno);
      }
    }

  }// end if has value
  else
  {
    // only search for key
    // has namespace?
    if (ns)
    {
      return q->addNode(std::make_shared<ExactAnnoKeySearch>(db,
        *ns,
        *name),
        wrapEmptyAnno);
    }
    else
    {
      return q->addNode(std::make_shared<ExactAnnoKeySearch>(db,
        *name),
        wrapEmptyAnno);
    }
  }
  // should never happen
  assert(false);
  return 0;
}

void JSONQueryParser::parseJoin(const DB& db,
                                DB::GetGSFuncT getGraphStorageFunc,
                                DB::GetAllGSFuncT getAllGraphStorageFunc,
                                const Json::Value join, std::shared_ptr<SingleAlternativeQuery> q,
  const std::map<std::uint64_t, size_t>& nodeIdToPos)
{
  // get left and right index
  if (join["left"].isUInt64() && join["right"].isUInt64())
  {
    auto leftID = join["left"].asUInt64();
    auto rightID = join["right"].asUInt64();

    auto itLeft = nodeIdToPos.find(leftID);
    auto itRight = nodeIdToPos.find(rightID);

    if (itLeft != nodeIdToPos.end() && itRight != nodeIdToPos.end())
    {

      auto op = join["op"].asString();
      if (op == "Precedence")
      {
        auto minDist = join["minDistance"].asUInt();
        auto maxDist = join["maxDistance"].asUInt();
        q->addOperator(std::make_shared<Precedence>(db, getGraphStorageFunc,
          minDist, maxDist),
          itLeft->second, itRight->second);
      }
      else if (op == "Inclusion")
      {
        q->addOperator(std::make_shared<Inclusion>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "Overlap")
      {
        q->addOperator(std::make_shared<Overlap>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "IdenticalCoverage")
      {
        q->addOperator(std::make_shared<IdenticalCoverage>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "Dominance")
      {

        std::string name = join["name"].isString() ? join["name"].asString() : "";

        if (join["edgeAnnotations"].isArray() && join["edgeAnnotations"].size() > 0)
        {
          auto anno = getEdgeAnno(db, join["edgeAnnotations"][0]);
          q->addOperator(std::make_shared<Dominance>(name, getAllGraphStorageFunc, db.strings, anno),
            itLeft->second, itRight->second);

        }
        else
        {

          auto minDist = join["minDistance"].asUInt();
          auto maxDist = join["maxDistance"].asUInt();
          if (minDist == 0 && maxDist == 0)
          {
            // unlimited range
            minDist = 1;
            maxDist = uintmax;
          }

          q->addOperator(std::make_shared<Dominance>(name, getAllGraphStorageFunc, db.strings,
            minDist, maxDist),
            itLeft->second, itRight->second);
        }
      }
      else if (op == "Pointing")
      {

        std::string name = join["name"].asString();

        if (join["edgeAnnotations"].isArray() && join["edgeAnnotations"].size() > 0)
        {
          auto anno = getEdgeAnno(db, join["edgeAnnotations"][0]);
          q->addOperator(std::make_shared<Pointing>(name, getAllGraphStorageFunc, db.strings, anno),
            itLeft->second, itRight->second);

        }
        else
        {

          auto minDist = join["minDistance"].asUInt();
          auto maxDist = join["maxDistance"].asUInt();

          if (minDist == 0 && maxDist == 0)
          {
            // unlimited range
            minDist = 1;
            maxDist = uintmax;
          }

          q->addOperator(std::make_shared<Pointing>(name, getAllGraphStorageFunc, db.strings, minDist, maxDist),
            itLeft->second, itRight->second);
        }
      }

    }

  }
}

Annotation JSONQueryParser::getEdgeAnno(const DB& db, const Json::Value& edgeAnno)
{

  std::uint32_t ns = 0;
  std::uint32_t name = 0;
  std::uint32_t value = 0;

  if (edgeAnno["textMatching"].asString() == "EXACT_EQUAL")
  {
    if (edgeAnno["namespace"].isString())
    {
      std::string nsStr = edgeAnno["namespace"].asString();
      auto search = db.strings.findID(nsStr);
      // if string is not found set to an invalid value
      ns = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
    if (edgeAnno["name"].isString())
    {
      std::string nameStr = edgeAnno["name"].asString();
      auto search = db.strings.findID(nameStr);
      // if string is not found set to an invalid value
      name = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
    if (edgeAnno["value"].isString())
    {
      std::string valueStr = edgeAnno["value"].asString();
      auto search = db.strings.findID(valueStr);
      // if string is not found set to an invalid value
      value = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
  }
  // TODO: what about regex?

  return Init::initAnnotation(name, value, ns);
}

bool JSONQueryParser::canReplaceRegex(const std::string& str)
{
  // Characters that have a meaning according to
  // https://github.com/google/re2/wiki/Syntax
  // Characters used in not supported functions are not included.
  if(str.find_first_of(".[]\\|*+?{}()^$") == std::string::npos)
  {
    // No meta character found in string, might be replaced
    RE2 regex(str);
    if(regex.ok())
    {
      return true;
    }
    else
    {
      // If there is an error during parsing this is still a regex (an invalid one).
      // Treating it like a exact string would not give the same result.
      return false;
    }
  }
  else
  {
    // contains special regex characters
    return false;
  }
}

JSONQueryParser::~JSONQueryParser()
{
}

<commit_msg>Only add the coverage based token filtering condition if the query explicitly asks for token (and not segmentation nodes in general)<commit_after>/*
   Copyright 2017 Thomas Krause <thomaskrause@posteo.de>

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#include "jsonqueryparser.h"
#include <annis/annosearch/exactannokeysearch.h>    // for ExactAnnoKeySearch
#include <annis/annosearch/exactannovaluesearch.h>  // for ExactAnnoValueSearch
#include <annis/annosearch/regexannosearch.h>       // for RegexAnnoSearch
#include <annis/operators/dominance.h>              // for Dominance
#include <annis/operators/identicalcoverage.h>      // for IdenticalCoverage
#include <annis/operators/identicalnode.h>
#include <annis/operators/inclusion.h>              // for Inclusion
#include <annis/operators/overlap.h>                // for Overlap
#include <annis/operators/pointing.h>               // for Pointing
#include <annis/operators/precedence.h>             // for Precedence
#include <annis/operators/partofsubcorpus.h>
#include <assert.h>                                 // for assert
#include <re2/re2.h>                                // for RE2
#include <limits>                                   // for numeric_limits
#include <map>                                      // for _Rb_tree_const_it...
#include <utility>                                  // for pair
#include "annis/db.h"                               // for DB
#include "annis/json/json.h"                        // for Value, ValueConst...
#include "annis/query/query.h"                            // for Query
#include "annis/queryconfig.h"                      // for QueryConfig
#include "annis/stringstorage.h"                    // for StringStorage
#include "annis/types.h"                          // for Edge, GraphStatistic

#include <boost/optional.hpp>

#include <functional>

using namespace annis;

JSONQueryParser::JSONQueryParser()
{
}
std::shared_ptr<Query> JSONQueryParser::parse(DB &db, std::istream& jsonStream, const QueryConfig config)
{
  return parse(db, db.f_getGraphStorage, db.f_getAllGraphStorages, jsonStream, config);
}

std::shared_ptr<Query> JSONQueryParser::parse(const DB& db, DB::GetGSFuncT getGraphStorageFunc,
                                              DB::GetAllGSFuncT getAllGraphStorageFunc,
                                              std::istream& jsonStream, const QueryConfig config)
{
  std::vector<std::shared_ptr<SingleAlternativeQuery>> result;

  // parse root as value
  Json::Value root;
  jsonStream >> root;

  // iterate over all alternatives
  const auto& alternatives = root["alternatives"];
  for(const auto& alt : alternatives)
  {
    std::shared_ptr<SingleAlternativeQuery> q = std::make_shared<SingleAlternativeQuery>(db, config);

    // add all nodes
    const auto& nodes = alt["nodes"];

    std::map<std::uint64_t, size_t> nodeIdToPos;
    boost::optional<size_t> firstNodePos;
    for (auto it = nodes.begin(); it != nodes.end(); it++)
    {
      auto& n = *it;
      size_t pos = parseNode(db, n, getGraphStorageFunc, q);
      nodeIdToPos[std::stoull(it.name())] = pos;
      if(!firstNodePos)
      {
        firstNodePos = pos;
      }
    }

    // add all joins
    const auto& joins = alt["joins"];
    for (auto it = joins.begin(); it != joins.end(); it++)
    {
      parseJoin(db, getGraphStorageFunc, getAllGraphStorageFunc, *it, q, nodeIdToPos);
    }

    // add all meta-data
    const auto& meta = alt["meta"];
    boost::optional<size_t> firstMetaIdx = boost::none;
    for (auto it = meta.begin(); it != meta.end(); it++)
    {
      auto& m = *it;

      // add an artificial node that describes the document/corpus node
      size_t metaNodeIdx = addNodeAnnotation(db, q, optStr(m["namespace"]),
            optStr(m["name"]), optStr(m["value"]),
            optStr(m["textMatching"]));

      if(firstMetaIdx)
      {
        // avoid nested loops by joining additional meta nodes with a "identical node"
        q->addOperator(std::make_shared<IdenticalNode>(db), metaNodeIdx, *firstMetaIdx);

      }
      else
      {
        firstMetaIdx = metaNodeIdx;
        // add a special join to the first node of the query
        q->addOperator(std::make_shared<PartOfSubCorpus>(getGraphStorageFunc, db.strings),
          metaNodeIdx, *firstNodePos);

      }
    }

    result.push_back(q);

  } // end for each alternative
  return std::make_shared<Query>(result);
}

std::shared_ptr<Query> JSONQueryParser::parseWithUpgradeableLock(DB &db,
                                                                 std::string queryAsJSON, boost::upgrade_lock<DBLoader>& lock,
                                                                 const QueryConfig config)
{
  DB::GetAllGSFuncT allFunc = [&db,&lock](ComponentType type, const std::string &name)
  {
    if(db.allGraphStoragesLoaded(type, name))
    {
      return db.getAllGraphStorages(type, name);
    }
    else
    {
      // loading the graph storages needs a unique lock to ensure nobody else is loading the same GS at the same time
      boost::upgrade_to_unique_lock<DBLoader> uniqueLock(lock);
      return db.getAllGraphStorages(type, name);
    }
  };

  DB::GetGSFuncT func = [&db,&lock](ComponentType type, const std::string &layer, const std::string &name)
  {
    if(db.isGraphStorageLoaded(type, layer, name))
    {
      return db.getGraphStorage(type, layer, name);
    }
    else
    {
      // loading the graph storages needs a unique lock to ensure nobody else is loading the same GS at the same time
      boost::upgrade_to_unique_lock<DBLoader> uniqueLock(lock);
      return db.getGraphStorage(type, layer, name);
    }
  };

  std::stringstream ss;
  ss << queryAsJSON;
  return annis::JSONQueryParser::parse(db, func, allFunc, ss, config);
}

size_t JSONQueryParser::parseNode(const DB& db, const Json::Value node, DB::GetGSFuncT getGraphStorageFunc, std::shared_ptr<SingleAlternativeQuery> q)
{

  // annotation search?
  if (node["nodeAnnotations"].isArray() && node["nodeAnnotations"].size() > 0)
  {
    // get the first one
    auto nodeAnno = node["nodeAnnotations"][0];

    return addNodeAnnotation(db, q, optStr(nodeAnno["namespace"]),
      optStr(nodeAnno["name"]), optStr(nodeAnno["value"]),
      optStr(nodeAnno["textMatching"]));

  }// end if annotation search
  else
  {
    // check for special non-annotation search constructs
    // token search?
    if (node["spannedText"].isString()
        || (node["token"].isBool() && node["token"].asBool()))
    {
      size_t n_pos = addNodeAnnotation(db, q, optStr(annis_ns), optStr(annis_tok),
                                       optStr(node["spannedText"]),
                                       optStr(node["spanTextMatching"]), true);

      // special treatment for explicit searches for token (tok="...)
      if(node["token"].isBool() && node["token"].asBool())
      {
        std::shared_ptr<const ReadableGraphStorage> covGS = getGraphStorageFunc(ComponentType::COVERAGE, annis_ns, "");
        if(covGS)
        {
          q->addFilter(n_pos, [&db, covGS] (const Match& m) -> bool
          {
            return static_cast<bool>(db.nodeAnnos.getAnnotations(m.node, db.getNamespaceStringID(), db.getTokStringID()))
                && covGS->getOutgoingEdges(m.node).empty();
          }, "is_token");
        }
      }

      return n_pos;
    }// end if token has spanned text
    else
    {
      // just search for any node
      return addNodeAnnotation(db, q, optStr(annis_ns), optStr(annis_node_type),
        boost::optional<std::string>("node"), boost::optional<std::string>("EXACT_EQUAL"));
    }
  } // end if special case

}

size_t JSONQueryParser::addNodeAnnotation(const DB& db,
  std::shared_ptr<SingleAlternativeQuery> q,
  boost::optional<std::string> ns,
  boost::optional<std::string> name,
  boost::optional<std::string> value,
  boost::optional<std::string> textMatching,
  bool wrapEmptyAnno)
{

  if (value)
  {
    bool exact = *textMatching == "EXACT_EQUAL";
    bool regex = *textMatching == "REGEXP_EQUAL";
    if(regex)
    {
      if(canReplaceRegex(*value))
      {
        exact = true;
      }
    }

    // search for the value
    if (exact)
    {
      // has namespace?
      if (ns)
      {
        return q->addNode(std::make_shared<ExactAnnoValueSearch>(db,
          *ns,
          *name,
          *value),
          wrapEmptyAnno);
      }
      else
      {
        return q->addNode(std::make_shared<ExactAnnoValueSearch>(db,
          *name,
          *value),
          wrapEmptyAnno);
      }
    }
    else if (regex)
    {
      // has namespace?
      if (ns)
      {
        return q->addNode(std::make_shared<RegexAnnoSearch>(db,
          *ns,
          *name,
          *value),
          wrapEmptyAnno);
      }
      else
      {
        return q->addNode(std::make_shared<RegexAnnoSearch>(db,
          *name,
          *value),
          wrapEmptyAnno);
      }
    }

  }// end if has value
  else
  {
    // only search for key
    // has namespace?
    if (ns)
    {
      return q->addNode(std::make_shared<ExactAnnoKeySearch>(db,
        *ns,
        *name),
        wrapEmptyAnno);
    }
    else
    {
      return q->addNode(std::make_shared<ExactAnnoKeySearch>(db,
        *name),
        wrapEmptyAnno);
    }
  }
  // should never happen
  assert(false);
  return 0;
}

void JSONQueryParser::parseJoin(const DB& db,
                                DB::GetGSFuncT getGraphStorageFunc,
                                DB::GetAllGSFuncT getAllGraphStorageFunc,
                                const Json::Value join, std::shared_ptr<SingleAlternativeQuery> q,
  const std::map<std::uint64_t, size_t>& nodeIdToPos)
{
  // get left and right index
  if (join["left"].isUInt64() && join["right"].isUInt64())
  {
    auto leftID = join["left"].asUInt64();
    auto rightID = join["right"].asUInt64();

    auto itLeft = nodeIdToPos.find(leftID);
    auto itRight = nodeIdToPos.find(rightID);

    if (itLeft != nodeIdToPos.end() && itRight != nodeIdToPos.end())
    {

      auto op = join["op"].asString();
      if (op == "Precedence")
      {
        auto minDist = join["minDistance"].asUInt();
        auto maxDist = join["maxDistance"].asUInt();
        q->addOperator(std::make_shared<Precedence>(db, getGraphStorageFunc,
          minDist, maxDist),
          itLeft->second, itRight->second);
      }
      else if (op == "Inclusion")
      {
        q->addOperator(std::make_shared<Inclusion>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "Overlap")
      {
        q->addOperator(std::make_shared<Overlap>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "IdenticalCoverage")
      {
        q->addOperator(std::make_shared<IdenticalCoverage>(db, getGraphStorageFunc), itLeft->second, itRight->second);
      }
      else if (op == "Dominance")
      {

        std::string name = join["name"].isString() ? join["name"].asString() : "";

        if (join["edgeAnnotations"].isArray() && join["edgeAnnotations"].size() > 0)
        {
          auto anno = getEdgeAnno(db, join["edgeAnnotations"][0]);
          q->addOperator(std::make_shared<Dominance>(name, getAllGraphStorageFunc, db.strings, anno),
            itLeft->second, itRight->second);

        }
        else
        {

          auto minDist = join["minDistance"].asUInt();
          auto maxDist = join["maxDistance"].asUInt();
          if (minDist == 0 && maxDist == 0)
          {
            // unlimited range
            minDist = 1;
            maxDist = uintmax;
          }

          q->addOperator(std::make_shared<Dominance>(name, getAllGraphStorageFunc, db.strings,
            minDist, maxDist),
            itLeft->second, itRight->second);
        }
      }
      else if (op == "Pointing")
      {

        std::string name = join["name"].asString();

        if (join["edgeAnnotations"].isArray() && join["edgeAnnotations"].size() > 0)
        {
          auto anno = getEdgeAnno(db, join["edgeAnnotations"][0]);
          q->addOperator(std::make_shared<Pointing>(name, getAllGraphStorageFunc, db.strings, anno),
            itLeft->second, itRight->second);

        }
        else
        {

          auto minDist = join["minDistance"].asUInt();
          auto maxDist = join["maxDistance"].asUInt();

          if (minDist == 0 && maxDist == 0)
          {
            // unlimited range
            minDist = 1;
            maxDist = uintmax;
          }

          q->addOperator(std::make_shared<Pointing>(name, getAllGraphStorageFunc, db.strings, minDist, maxDist),
            itLeft->second, itRight->second);
        }
      }

    }

  }
}

Annotation JSONQueryParser::getEdgeAnno(const DB& db, const Json::Value& edgeAnno)
{

  std::uint32_t ns = 0;
  std::uint32_t name = 0;
  std::uint32_t value = 0;

  if (edgeAnno["textMatching"].asString() == "EXACT_EQUAL")
  {
    if (edgeAnno["namespace"].isString())
    {
      std::string nsStr = edgeAnno["namespace"].asString();
      auto search = db.strings.findID(nsStr);
      // if string is not found set to an invalid value
      ns = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
    if (edgeAnno["name"].isString())
    {
      std::string nameStr = edgeAnno["name"].asString();
      auto search = db.strings.findID(nameStr);
      // if string is not found set to an invalid value
      name = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
    if (edgeAnno["value"].isString())
    {
      std::string valueStr = edgeAnno["value"].asString();
      auto search = db.strings.findID(valueStr);
      // if string is not found set to an invalid value
      value = search.first ? search.second : std::numeric_limits<std::uint32_t>::max();
    }
  }
  // TODO: what about regex?

  return Init::initAnnotation(name, value, ns);
}

bool JSONQueryParser::canReplaceRegex(const std::string& str)
{
  // Characters that have a meaning according to
  // https://github.com/google/re2/wiki/Syntax
  // Characters used in not supported functions are not included.
  if(str.find_first_of(".[]\\|*+?{}()^$") == std::string::npos)
  {
    // No meta character found in string, might be replaced
    RE2 regex(str);
    if(regex.ok())
    {
      return true;
    }
    else
    {
      // If there is an error during parsing this is still a regex (an invalid one).
      // Treating it like a exact string would not give the same result.
      return false;
    }
  }
  else
  {
    // contains special regex characters
    return false;
  }
}

JSONQueryParser::~JSONQueryParser()
{
}

<|endoftext|>


<commit_before>#include "OptionsManager.h"

#include <fstream>
#include <iostream>

#include <boost/filesystem.hpp>

#include <spotify/json.hpp>

#include "codecs/OptionsCodec.h"

OptionsManager::OptionsManager(std::string optionsFilename)
{
    loadOptions(optionsFilename);
}

void OptionsManager::loadOptions(std::string optionsFilename)
{
    std::ifstream ifs(optionsFilename);
    if (!ifs.good())
    {
        throw std::runtime_error("Could not open options file");
    }

    std::string str{std::istreambuf_iterator<char>(ifs),
                    std::istreambuf_iterator<char>()};
    try
    {
        mOptions = spotify::json::decode<Options>(str.c_str());
    }
    catch (spotify::json::decode_exception e)
    {
        std::cout << "spotify::json::decode_exception encountered at "
            << e.offset()
            << ": "
            << e.what();
        throw;
    }
    mOptions.filename = optionsFilename;

    createOutputDirectory(optionsFilename);
}

void OptionsManager::createOutputDirectory(std::string optionsFilename)
{
    // TODO(hryniuk): move it elsewhere
    auto outputDirectory = mOptions.outputDirectory;
    boost::filesystem::path p(optionsFilename);
    p.remove_filename();
    p.append(outputDirectory);
    boost::filesystem::create_directories(p);
    auto relativeOutputDirectory = p.string();
    mOptions.relativeOutputDirectory = relativeOutputDirectory;
}

const Options& OptionsManager::getOptions() const
{
    return mOptions;
}

<commit_msg>Catch const reference<commit_after>#include "OptionsManager.h"

#include <fstream>
#include <iostream>

#include <boost/filesystem.hpp>

#include <spotify/json.hpp>

#include "codecs/OptionsCodec.h"

OptionsManager::OptionsManager(std::string optionsFilename)
{
    loadOptions(optionsFilename);
}

void OptionsManager::loadOptions(std::string optionsFilename)
{
    std::ifstream ifs(optionsFilename);
    if (!ifs.good())
    {
        throw std::runtime_error("Could not open options file");
    }

    std::string str{std::istreambuf_iterator<char>(ifs),
                    std::istreambuf_iterator<char>()};
    try
    {
        mOptions = spotify::json::decode<Options>(str.c_str());
    }
    catch (const spotify::json::decode_exception& e)
    {
        std::cout << "spotify::json::decode_exception encountered at "
            << e.offset()
            << ": "
            << e.what();
        throw;
    }
    mOptions.filename = optionsFilename;

    createOutputDirectory(optionsFilename);
}

void OptionsManager::createOutputDirectory(std::string optionsFilename)
{
    // TODO(hryniuk): move it elsewhere
    auto outputDirectory = mOptions.outputDirectory;
    boost::filesystem::path p(optionsFilename);
    p.remove_filename();
    p.append(outputDirectory);
    boost::filesystem::create_directories(p);
    auto relativeOutputDirectory = p.string();
    mOptions.relativeOutputDirectory = relativeOutputDirectory;
}

const Options& OptionsManager::getOptions() const
{
    return mOptions;
}

<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkContourWidget.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkContourWidget.h"
#include "vtkOrientedGlyphContourRepresentation.h"
#include "vtkCommand.h"
#include "vtkCallbackCommand.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkSphereSource.h"
#include "vtkProperty.h"
#include "vtkProperty2D.h"
#include "vtkEvent.h"
#include "vtkWidgetEvent.h"
#include "vtkPolyData.h"

vtkCxxRevisionMacro(vtkContourWidget, "1.24");
vtkStandardNewMacro(vtkContourWidget);

//----------------------------------------------------------------------
vtkContourWidget::vtkContourWidget()
{
  this->ManagesCursor = 0;

  this->WidgetState = vtkContourWidget::Start;
  this->CurrentHandle = 0;

  // These are the event callbacks supported by this widget
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
                                          vtkWidgetEvent::Select,
                                          this, vtkContourWidget::SelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonPressEvent,
                                          vtkWidgetEvent::AddFinalPoint,
                                          this, vtkContourWidget::AddFinalPointAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent,
                                          vtkWidgetEvent::Move,
                                          this, vtkContourWidget::MoveAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent,
                                          vtkWidgetEvent::EndSelect,
                                          this, vtkContourWidget::EndSelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent,
                                          vtkEvent::NoModifier, 127, 1, "Delete",
                                          vtkWidgetEvent::Delete,
                                          this, vtkContourWidget::DeleteAction);

  this->CreateDefaultRepresentation();

}

//----------------------------------------------------------------------
vtkContourWidget::~vtkContourWidget()
{
}

//----------------------------------------------------------------------
void vtkContourWidget::CreateDefaultRepresentation()
{
  if ( ! this->WidgetRep )
    {
    vtkOrientedGlyphContourRepresentation *rep =
      vtkOrientedGlyphContourRepresentation::New();

    this->WidgetRep = rep;

    vtkSphereSource *ss = vtkSphereSource::New();
    ss->SetRadius(0.5);
    rep->SetActiveCursorShape( ss->GetOutput() );
    ss->Delete();

    rep->GetProperty()->SetColor(.25,1.0,.25);

    vtkProperty *property =
        vtkProperty::SafeDownCast(rep->GetActiveProperty());
    if (property)
      {
      property->SetRepresentationToSurface();
      property->SetAmbient(0.1);
      property->SetDiffuse(0.9);
      property->SetSpecular(0.0);
      }
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::SetEnabled(int enabling)
{
  // The handle widgets are not actually enabled until they are placed.
  // The handle widgets take their representation from the vtkContourRepresentation.
  if ( enabling )
    {
    if ( this->WidgetState == vtkContourWidget::Start )
      {
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep)->VisibilityOff();
      }
    else
      {
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep)->VisibilityOn();
      }
    }

  this->Superclass::SetEnabled(enabling);
}

// The following methods are the callbacks that the measure widget responds to.
//-------------------------------------------------------------------------
void vtkContourWidget::SelectAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  int X = self->Interactor->GetEventPosition()[0];
  int Y = self->Interactor->GetEventPosition()[1];
  double pos[2];
  pos[0] = X;
  pos[1] = Y;

  switch ( self->WidgetState )
    {
    case vtkContourWidget::Start:
    case vtkContourWidget::Define:
      self->AddNode();
      break;
    case vtkContourWidget::Manipulate:
      if ( rep->ActivateNode(X,Y) )
        {
        self->Superclass::StartInteraction();
        self->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
        self->StartInteraction();
        rep->SetCurrentOperationToTranslate();
        rep->StartWidgetInteraction(pos);
        self->EventCallbackCommand->SetAbortFlag(1);
        }
      else if ( rep->AddNodeOnContour( X, Y ) )
        {
        if ( rep->ActivateNode(X,Y) )
          {
          rep->SetCurrentOperationToTranslate();
          rep->StartWidgetInteraction(pos);
          }
        self->EventCallbackCommand->SetAbortFlag(1);
        }
      break;
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::AddFinalPointAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( self->WidgetState !=  vtkContourWidget::Manipulate &&
       rep->GetNumberOfNodes() >= 1 )
    {
    self->AddNode();
    self->WidgetState = vtkContourWidget::Manipulate;
    self->EventCallbackCommand->SetAbortFlag(1);
    self->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//------------------------------------------------------------------------
void vtkContourWidget::AddNode()
{
  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // If the rep already has at least 2 nodes, check how close we are to
  // the first
  vtkContourRepresentation* rep =
    reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep);

  int numNodes = rep->GetNumberOfNodes();
  if ( numNodes > 1 )
    {
    int pixelTolerance2 = rep->GetPixelTolerance();
    pixelTolerance2 *= pixelTolerance2;

    double displayPos[2];
    if ( !rep->GetNthNodeDisplayPosition( 0, displayPos ) )
      {
      vtkErrorMacro("Can't get first node display position!");
      return;
      }

    if ( (X - displayPos[0]) * (X - displayPos[0]) +
         (Y - displayPos[1]) * (Y - displayPos[1]) <
         pixelTolerance2 && numNodes > 2 )
      {
      // yes - we have made a loop. Stop defining and switch to
      // manipulate mode
      this->WidgetState = vtkContourWidget::Manipulate;
      rep->ClosedLoopOn();
      this->Render();
      this->EventCallbackCommand->SetAbortFlag(1);
      this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
      return;
      }
    }

  if ( rep->AddNodeAtDisplayPosition( X, Y ) )
    {
    if ( this->WidgetState == vtkContourWidget::Start )
      {
      this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
      }

    this->WidgetState = vtkContourWidget::Define;
    rep->VisibilityOn();
    this->EventCallbackCommand->SetAbortFlag(1);
    this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::DeleteAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);

  if ( self->WidgetState == vtkContourWidget::Start )
    {
    return;
    }

  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( self->WidgetState == vtkContourWidget::Define )
    {
    if (rep->DeleteLastNode())
      {
      self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
      }
    }
  else
    {
    int X = self->Interactor->GetEventPosition()[0];
    int Y = self->Interactor->GetEventPosition()[1];
    rep->ActivateNode( X, Y );
    if ( rep->DeleteActiveNode() )
      {
      self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
      }
    rep->ActivateNode( X, Y );
    if ( rep->GetNumberOfNodes() < 3 )
      {
      rep->ClosedLoopOff();
      self->WidgetState = vtkContourWidget::Define;
      }
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::MoveAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);

  if ( self->WidgetState == vtkContourWidget::Start ||
       self->WidgetState == vtkContourWidget::Define )
    {
    return;
    }

  int X = self->Interactor->GetEventPosition()[0];
  int Y = self->Interactor->GetEventPosition()[1];
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( rep->GetCurrentOperation() == vtkContourRepresentation::Inactive )
    {
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep)->
      ComputeInteractionState( X, Y );
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep)->
      ActivateNode( X, Y );
    }
  else
    {
    double pos[2];
    pos[0] = X;
    pos[1] = Y;
    self->WidgetRep->WidgetInteraction(pos);
    self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
    }

  if ( self->WidgetRep->GetNeedToRender() )
    {
    self->Render();
    self->WidgetRep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::EndSelectAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  // Do nothing if inactive
  if ( rep->GetCurrentOperation() == vtkContourRepresentation::Inactive )
    {
    return;
    }

  rep->SetCurrentOperationToInactive();
  self->EventCallbackCommand->SetAbortFlag(1);
  self->Superclass::EndInteraction();
  self->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);

  if ( self->WidgetRep->GetNeedToRender() )
    {
    self->Render();
    self->WidgetRep->NeedToRenderOff();
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::Initialize( vtkPolyData * pd, int state )
{
  if (!this->GetEnabled())
    {
    vtkErrorMacro(<<"Enable widget before initializing");
    }

  if (this->WidgetRep)
    {
    vtkContourRepresentation *rep =
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep);

    if ( pd == NULL )
      {
      while( rep->DeleteLastNode() )
        {
        ;
        }
      rep->ClosedLoopOff();
      this->Render();
      rep->NeedToRenderOff();
      rep->VisibilityOff();
      this->WidgetState = vtkContourWidget::Start;
      }
    else
      {
      rep->Initialize( pd );
      this->WidgetState = (rep->GetClosedLoop() || state == 1 ) ?
        vtkContourWidget::Manipulate : vtkContourWidget::Define;
      }
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
  this->Superclass::PrintSelf(os,indent);

}
<commit_msg>BUG: state should be Define if nnodes < 2, otherwise if we deleted a node from a 3 node contour the resulting 2 node contour would not be editable<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkContourWidget.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkContourWidget.h"
#include "vtkOrientedGlyphContourRepresentation.h"
#include "vtkCommand.h"
#include "vtkCallbackCommand.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkObjectFactory.h"
#include "vtkRenderer.h"
#include "vtkWidgetCallbackMapper.h"
#include "vtkSphereSource.h"
#include "vtkProperty.h"
#include "vtkProperty2D.h"
#include "vtkEvent.h"
#include "vtkWidgetEvent.h"
#include "vtkPolyData.h"

vtkCxxRevisionMacro(vtkContourWidget, "1.25");
vtkStandardNewMacro(vtkContourWidget);

//----------------------------------------------------------------------
vtkContourWidget::vtkContourWidget()
{
  this->ManagesCursor = 0;

  this->WidgetState = vtkContourWidget::Start;
  this->CurrentHandle = 0;

  // These are the event callbacks supported by this widget
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonPressEvent,
                                          vtkWidgetEvent::Select,
                                          this, vtkContourWidget::SelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::RightButtonPressEvent,
                                          vtkWidgetEvent::AddFinalPoint,
                                          this, vtkContourWidget::AddFinalPointAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::MouseMoveEvent,
                                          vtkWidgetEvent::Move,
                                          this, vtkContourWidget::MoveAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::LeftButtonReleaseEvent,
                                          vtkWidgetEvent::EndSelect,
                                          this, vtkContourWidget::EndSelectAction);
  this->CallbackMapper->SetCallbackMethod(vtkCommand::KeyPressEvent,
                                          vtkEvent::NoModifier, 127, 1, "Delete",
                                          vtkWidgetEvent::Delete,
                                          this, vtkContourWidget::DeleteAction);

  this->CreateDefaultRepresentation();

}

//----------------------------------------------------------------------
vtkContourWidget::~vtkContourWidget()
{
}

//----------------------------------------------------------------------
void vtkContourWidget::CreateDefaultRepresentation()
{
  if ( ! this->WidgetRep )
    {
    vtkOrientedGlyphContourRepresentation *rep =
      vtkOrientedGlyphContourRepresentation::New();

    this->WidgetRep = rep;

    vtkSphereSource *ss = vtkSphereSource::New();
    ss->SetRadius(0.5);
    rep->SetActiveCursorShape( ss->GetOutput() );
    ss->Delete();

    rep->GetProperty()->SetColor(.25,1.0,.25);

    vtkProperty *property =
        vtkProperty::SafeDownCast(rep->GetActiveProperty());
    if (property)
      {
      property->SetRepresentationToSurface();
      property->SetAmbient(0.1);
      property->SetDiffuse(0.9);
      property->SetSpecular(0.0);
      }
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::SetEnabled(int enabling)
{
  // The handle widgets are not actually enabled until they are placed.
  // The handle widgets take their representation from the vtkContourRepresentation.
  if ( enabling )
    {
    if ( this->WidgetState == vtkContourWidget::Start )
      {
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep)->VisibilityOff();
      }
    else
      {
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep)->VisibilityOn();
      }
    }

  this->Superclass::SetEnabled(enabling);
}

// The following methods are the callbacks that the measure widget responds to.
//-------------------------------------------------------------------------
void vtkContourWidget::SelectAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  int X = self->Interactor->GetEventPosition()[0];
  int Y = self->Interactor->GetEventPosition()[1];
  double pos[2];
  pos[0] = X;
  pos[1] = Y;

  switch ( self->WidgetState )
    {
    case vtkContourWidget::Start:
    case vtkContourWidget::Define:
      self->AddNode();
      break;
    case vtkContourWidget::Manipulate:
      if ( rep->ActivateNode(X,Y) )
        {
        self->Superclass::StartInteraction();
        self->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
        self->StartInteraction();
        rep->SetCurrentOperationToTranslate();
        rep->StartWidgetInteraction(pos);
        self->EventCallbackCommand->SetAbortFlag(1);
        }
      else if ( rep->AddNodeOnContour( X, Y ) )
        {
        if ( rep->ActivateNode(X,Y) )
          {
          rep->SetCurrentOperationToTranslate();
          rep->StartWidgetInteraction(pos);
          }
        self->EventCallbackCommand->SetAbortFlag(1);
        }
      break;
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::AddFinalPointAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( self->WidgetState !=  vtkContourWidget::Manipulate &&
       rep->GetNumberOfNodes() >= 1 )
    {
    self->AddNode();
    self->WidgetState = vtkContourWidget::Manipulate;
    self->EventCallbackCommand->SetAbortFlag(1);
    self->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//------------------------------------------------------------------------
void vtkContourWidget::AddNode()
{
  int X = this->Interactor->GetEventPosition()[0];
  int Y = this->Interactor->GetEventPosition()[1];

  // If the rep already has at least 2 nodes, check how close we are to
  // the first
  vtkContourRepresentation* rep =
    reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep);

  int numNodes = rep->GetNumberOfNodes();
  if ( numNodes > 1 )
    {
    int pixelTolerance2 = rep->GetPixelTolerance();
    pixelTolerance2 *= pixelTolerance2;

    double displayPos[2];
    if ( !rep->GetNthNodeDisplayPosition( 0, displayPos ) )
      {
      vtkErrorMacro("Can't get first node display position!");
      return;
      }

    if ( (X - displayPos[0]) * (X - displayPos[0]) +
         (Y - displayPos[1]) * (Y - displayPos[1]) <
         pixelTolerance2 && numNodes > 2 )
      {
      // yes - we have made a loop. Stop defining and switch to
      // manipulate mode
      this->WidgetState = vtkContourWidget::Manipulate;
      rep->ClosedLoopOn();
      this->Render();
      this->EventCallbackCommand->SetAbortFlag(1);
      this->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);
      return;
      }
    }

  if ( rep->AddNodeAtDisplayPosition( X, Y ) )
    {
    if ( this->WidgetState == vtkContourWidget::Start )
      {
      this->InvokeEvent(vtkCommand::StartInteractionEvent,NULL);
      }

    this->WidgetState = vtkContourWidget::Define;
    rep->VisibilityOn();
    this->EventCallbackCommand->SetAbortFlag(1);
    this->InvokeEvent(vtkCommand::InteractionEvent,NULL);
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::DeleteAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);

  if ( self->WidgetState == vtkContourWidget::Start )
    {
    return;
    }

  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( self->WidgetState == vtkContourWidget::Define )
    {
    if (rep->DeleteLastNode())
      {
      self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
      }
    }
  else
    {
    int X = self->Interactor->GetEventPosition()[0];
    int Y = self->Interactor->GetEventPosition()[1];
    rep->ActivateNode( X, Y );
    if ( rep->DeleteActiveNode() )
      {
      self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
      }
    rep->ActivateNode( X, Y );
    int nnode = rep->GetNumberOfNodes();
    if ( nnode < 3 )
      {
      rep->ClosedLoopOff();
      if( nnode < 2 )
        {
        self->WidgetState = vtkContourWidget::Define;
        }
      }
    }

  if ( rep->GetNeedToRender() )
    {
    self->Render();
    rep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::MoveAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);

  if ( self->WidgetState == vtkContourWidget::Start ||
       self->WidgetState == vtkContourWidget::Define )
    {
    return;
    }

  int X = self->Interactor->GetEventPosition()[0];
  int Y = self->Interactor->GetEventPosition()[1];
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  if ( rep->GetCurrentOperation() == vtkContourRepresentation::Inactive )
    {
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep)->
      ComputeInteractionState( X, Y );
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep)->
      ActivateNode( X, Y );
    }
  else
    {
    double pos[2];
    pos[0] = X;
    pos[1] = Y;
    self->WidgetRep->WidgetInteraction(pos);
    self->InvokeEvent(vtkCommand::InteractionEvent,NULL);
    }

  if ( self->WidgetRep->GetNeedToRender() )
    {
    self->Render();
    self->WidgetRep->NeedToRenderOff();
    }
}

//-------------------------------------------------------------------------
void vtkContourWidget::EndSelectAction(vtkAbstractWidget *w)
{
  vtkContourWidget *self = reinterpret_cast<vtkContourWidget*>(w);
  vtkContourRepresentation *rep =
    reinterpret_cast<vtkContourRepresentation*>(self->WidgetRep);

  // Do nothing if inactive
  if ( rep->GetCurrentOperation() == vtkContourRepresentation::Inactive )
    {
    return;
    }

  rep->SetCurrentOperationToInactive();
  self->EventCallbackCommand->SetAbortFlag(1);
  self->Superclass::EndInteraction();
  self->InvokeEvent(vtkCommand::EndInteractionEvent,NULL);

  if ( self->WidgetRep->GetNeedToRender() )
    {
    self->Render();
    self->WidgetRep->NeedToRenderOff();
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::Initialize( vtkPolyData * pd, int state )
{
  if (!this->GetEnabled())
    {
    vtkErrorMacro(<<"Enable widget before initializing");
    }

  if (this->WidgetRep)
    {
    vtkContourRepresentation *rep =
      reinterpret_cast<vtkContourRepresentation*>(this->WidgetRep);

    if ( pd == NULL )
      {
      while( rep->DeleteLastNode() )
        {
        ;
        }
      rep->ClosedLoopOff();
      this->Render();
      rep->NeedToRenderOff();
      rep->VisibilityOff();
      this->WidgetState = vtkContourWidget::Start;
      }
    else
      {
      rep->Initialize( pd );
      this->WidgetState = (rep->GetClosedLoop() || state == 1 ) ?
        vtkContourWidget::Manipulate : vtkContourWidget::Define;
      }
    }
}

//----------------------------------------------------------------------
void vtkContourWidget::PrintSelf(ostream& os, vtkIndent indent)
{
  //Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
  this->Superclass::PrintSelf(os,indent);

}
<|endoftext|>


<commit_before>#include "extract_sv_reads/Parse.hpp"
#include "extract_sv_reads/Alignment.hpp"
#include "extract_sv_reads/Options.hpp"
#include "extract_sv_reads/SamReader.hpp"
#include "extract_sv_reads/SamWriter.hpp"
#include "extract_sv_reads/ShrunkSamWriter.hpp"

#include <hts.h>
#include <sam.h>

#include <boost/format.hpp>

#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdexcept>

using boost::format;
namespace {
    template<typename R>
        void parse_file(Options const& opts, SamReader& reader, R const& disc, R const& split) {
            bam1_t *aln = bam_init1();
            int discordant_flag = BAM_FPROPER_PAIR | BAM_FMUNMAP | BAM_FSUPPLEMENTARY;

            while (reader.next(aln)) {
                if (((aln->core.flag) & discordant_flag) == 0)
                    disc.write(aln);

                uint8_t *sa = bam_aux_get(aln, "SA");

                if (sa != 0) {
                    std::string sa_string = bam_aux2Z(sa);

                    char const* beg = sa_string.data();
                    char const* end = beg + sa_string.size();
                    SimpleTokenizer tok(beg, end, ';');
                    std::string first_sa;
                    if (!tok.extract(first_sa)) {
                        throw std::runtime_error(str(format(
                                        "Error parsing SA tag: %1%"
                                        ) % sa_string));
                    }

                    if (tok.next_delim() == end) {
                        Alignment first(aln, reader.header());
                        Alignment second(first_sa.data(), first_sa.data() + first_sa.size());

                        Alignment const* left = &first;
                        Alignment const* right = &second;

                        if (left->SQO > right->SQO) {
                            right = &first;
                            left = &second;
                        }

                        if (mno(*left, *right) < opts.min_non_overlap)
                            continue;

                        if (should_check(*left, *right)) {
                            if ((abs(insert_size(*left, *right)) < opts.min_indel_size)
                                    || ((desert(*left, *right) > 0)
                                        && (desert(*left, *right) - (int) std::max(0, insert_size(*left, *right))) > opts.max_unmapped_bases)) {
                                continue;
                            }
                        }

                        char *qname =  bam_get_qname(aln);
                        if ((aln->core.flag & 64) == 64)
                            qname[0] = 'A';
                        else
                            qname[0] = 'B';

                        split.write(aln);
                    }
                }
            }
            bam_destroy1(aln);
        }
    void run(Options const& opts) {

        SamReader reader(opts.input_file.c_str(), opts.reference.c_str(), opts.input_threads);

        int skip_flag = BAM_FUNMAP | BAM_FQCFAIL | BAM_FSECONDARY;
        if (opts.exclude_dups) {
            skip_flag = skip_flag | BAM_FDUP;
        }
        reader.skip_flags(skip_flag);

        if (opts.shrink_bam) {
            ShrunkSamWriter disc(opts.discordant_output_file.c_str(), "wb", reader.header());
            ShrunkSamWriter split(opts.splitter_output_file.c_str(), "wb", reader.header());
            parse_file(opts, reader, disc, split);
        }
        else {
            SamWriter disc(opts.discordant_output_file.c_str(), "wb", reader.header());
            SamWriter split(opts.splitter_output_file.c_str(), "wb", reader.header());
            parse_file(opts, reader, disc, split);
        }
    }

}

int main(int argc, char** argv) {
    try {
        Options opts = Options(argc, argv);
        run(opts);
    }
    catch (std::exception const& ex) {
        std::cerr << "ERROR: " << ex.what() << "\n";
        return 1;
    }
    return 0;
}
<commit_msg>Don't skip secondaries<commit_after>#include "extract_sv_reads/Parse.hpp"
#include "extract_sv_reads/Alignment.hpp"
#include "extract_sv_reads/Options.hpp"
#include "extract_sv_reads/SamReader.hpp"
#include "extract_sv_reads/SamWriter.hpp"
#include "extract_sv_reads/ShrunkSamWriter.hpp"

#include <hts.h>
#include <sam.h>

#include <boost/format.hpp>

#include <string>
#include <iostream>
#include <stdlib.h>
#include <stdexcept>

using boost::format;
namespace {
    template<typename R>
        void parse_file(Options const& opts, SamReader& reader, R const& disc, R const& split) {
            bam1_t *aln = bam_init1();
            int discordant_flag = BAM_FPROPER_PAIR | BAM_FMUNMAP | BAM_FSUPPLEMENTARY;

            while (reader.next(aln)) {
                if (((aln->core.flag) & discordant_flag) == 0)
                    disc.write(aln);

                uint8_t *sa = bam_aux_get(aln, "SA");

                if (sa != 0) {
                    std::string sa_string = bam_aux2Z(sa);

                    char const* beg = sa_string.data();
                    char const* end = beg + sa_string.size();
                    SimpleTokenizer tok(beg, end, ';');
                    std::string first_sa;
                    if (!tok.extract(first_sa)) {
                        throw std::runtime_error(str(format(
                                        "Error parsing SA tag: %1%"
                                        ) % sa_string));
                    }

                    if (tok.next_delim() == end) {
                        Alignment first(aln, reader.header());
                        Alignment second(first_sa.data(), first_sa.data() + first_sa.size());

                        Alignment const* left = &first;
                        Alignment const* right = &second;

                        if (left->SQO > right->SQO) {
                            right = &first;
                            left = &second;
                        }

                        if (mno(*left, *right) < opts.min_non_overlap)
                            continue;

                        if (should_check(*left, *right)) {
                            if ((abs(insert_size(*left, *right)) < opts.min_indel_size)
                                    || ((desert(*left, *right) > 0)
                                        && (desert(*left, *right) - (int) std::max(0, insert_size(*left, *right))) > opts.max_unmapped_bases)) {
                                continue;
                            }
                        }

                        char *qname =  bam_get_qname(aln);
                        if ((aln->core.flag & 64) == 64)
                            qname[0] = 'A';
                        else
                            qname[0] = 'B';

                        split.write(aln);
                    }
                }
            }
            bam_destroy1(aln);
        }
    void run(Options const& opts) {

        SamReader reader(opts.input_file.c_str(), opts.reference.c_str(), opts.input_threads);

        int skip_flag = BAM_FUNMAP | BAM_FQCFAIL;
        if (opts.exclude_dups) {
            skip_flag = skip_flag | BAM_FDUP;
        }
        reader.skip_flags(skip_flag);

        if (opts.shrink_bam) {
            ShrunkSamWriter disc(opts.discordant_output_file.c_str(), "wb", reader.header());
            ShrunkSamWriter split(opts.splitter_output_file.c_str(), "wb", reader.header());
            parse_file(opts, reader, disc, split);
        }
        else {
            SamWriter disc(opts.discordant_output_file.c_str(), "wb", reader.header());
            SamWriter split(opts.splitter_output_file.c_str(), "wb", reader.header());
            parse_file(opts, reader, disc, split);
        }
    }

}

int main(int argc, char** argv) {
    try {
        Options opts = Options(argc, argv);
        run(opts);
    }
    catch (std::exception const& ex) {
        std::cerr << "ERROR: " << ex.what() << "\n";
        return 1;
    }
    return 0;
}
<|endoftext|>


<commit_before>/*!
 * \file shader_filled_path.cpp
 * \brief file shader_filled_path.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <vector>
#include <fastuidraw/path.hpp>
#include <fastuidraw/tessellated_path.hpp>
#include <fastuidraw/text/font.hpp>
#include <fastuidraw/text/glyph.hpp>
#include <fastuidraw/text/glyph_render_data_banded_rays.hpp>
#include <fastuidraw/text/glyph_render_data_restricted_rays.hpp>
#include <fastuidraw/painter/shader_filled_path.hpp>
#include "../private/util_private.hpp"
#include "../private/bounding_box.hpp"
#include "../private/bezier_util.hpp"

namespace
{
  /* RestrictedRays, although slower in performance, gives more robust
   * anti-aliasing when zoomed in a great deal than BandedRays.
   */
#if 1
  typedef fastuidraw::GlyphRenderDataRestrictedRays RenderData;
  const enum fastuidraw::glyph_type GlyphType = fastuidraw::restricted_rays_glyph;

  inline
  void
  finalize_data(enum fastuidraw::PainterEnums::fill_rule_t f,
                const fastuidraw::BoundingBox<float> &bbox,
                fastuidraw::GlyphRenderDataRestrictedRays *data)
  {
    data->finalize(f, bbox.as_rect(),
                   4, //aim for 4 curves per box
                   12, //recurse up to 12 times.
                   fastuidraw::vec2(-1.0f, -1.0f));
  }

#else
  typedef fastuidraw::GlyphRenderDataBandedRays RenderData;
  const enum fastuidraw::glyph_type GlyphType = fastuidraw::banded_rays_glyph;

  inline
  void
  finalize_data(enum fastuidraw::PainterEnums::fill_rule_t f,
                const fastuidraw::BoundingBox<float> &bbox,
                fastuidraw::GlyphRenderDataBandedRays *data)
  {
    data->finalize(f, bbox.as_rect());
  }

#endif

  class BuilderPrivate
  {
  public:
    RenderData m_data;
    fastuidraw::BoundingBox<float> m_bbox;
  };

  class AddPath
  {
  public:
    explicit
    AddPath(float tol,
            const fastuidraw::Path *path,
            fastuidraw::ShaderFilledPath::Builder *b):
      m_tol(tol),
      m_b(b),
      m_path(path),
      m_tess(nullptr)
    {}

    void
    add_to_render_data(void);

  private:
    void
    add_contour(unsigned int contour);

    void
    add_interpolator(const fastuidraw::PathContour *contour,
                     unsigned int contour_id, unsigned int interpolator_id);

    void
    add_interpolator_from_tess(unsigned int contour_id, unsigned int interpolator_id);

    float m_tol;
    fastuidraw::ShaderFilledPath::Builder *m_b;
    const fastuidraw::Path *m_path;
    const fastuidraw::TessellatedPath *m_tess;
  };

  class PerFillRule
  {
  public:
    fastuidraw::vecN<fastuidraw::PainterAttribute, 4> m_attribs;
    fastuidraw::vecN<fastuidraw::PainterIndex, 6> m_indices;
    fastuidraw::vecN<fastuidraw::GlyphAttribute, RenderData::glyph_num_attributes> m_glyph_attribs;
  };

  class ShaderFilledPathPrivate
  {
  public:
    explicit
    ShaderFilledPathPrivate(BuilderPrivate &B);

    ~ShaderFilledPathPrivate();

    const PerFillRule&
    per_fill_rule(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
                  enum fastuidraw::PainterEnums::fill_rule_t fill_rule);

  private:
    void
    update_attribute_data(void);

    fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> m_atlas;
    fastuidraw::BoundingBox<float> m_bbox;
    int m_allocation;
    std::vector<fastuidraw::generic_data> m_gpu_data;
    RenderData::query_info m_query_data;

    fastuidraw::vecN<PerFillRule, fastuidraw::PainterEnums::fill_rule_data_count> m_per_fill_rule;
    unsigned int m_number_times_atlas_cleared;
  };
}

////////////////////////////////
// AddPath methods
void
AddPath::
add_to_render_data(void)
{
  for (unsigned int i = 0, endi = m_path->number_contours(); i < endi; ++i)
    {
      add_contour(i);
    }
}

void
AddPath::
add_contour(unsigned int contour_id)
{
  using namespace fastuidraw;

  reference_counted_ptr<const PathContour> contour(m_path->contour(contour_id));
  if (contour->number_interpolators() == 0)
    {
      return;
    }

  m_b->move_to(contour->point(0));
  for (unsigned int i = 0, endi = contour->number_interpolators(); i < endi; ++i)
    {
      add_interpolator(contour.get(), contour_id, i);
    }

  if (!contour->closed())
    {
      m_b->line_to(contour->point(0));
    }
}

void
AddPath::
add_interpolator(const fastuidraw::PathContour *contour,
                 unsigned int contour_id, unsigned int interpolator_id)
{
  using namespace fastuidraw;

  enum return_code R;
  const PathContour::interpolator_base *interpolator(contour->interpolator(interpolator_id).get());

  R = interpolator->add_to_builder(m_b, m_tol);
  if (R == routine_fail)
    {
      add_interpolator_from_tess(contour_id, interpolator_id);
    }
}

void
AddPath::
add_interpolator_from_tess(unsigned int contour_id, unsigned int interpolator_id)
{
  using namespace fastuidraw;

  float half_tol(0.5f * m_tol);
  if (!m_tess)
    {
      m_tess = m_path->tessellation(half_tol).get();
    }

  /* walk through the segments of the named interpolator */
  c_array<const TessellatedPath::segment> segments;
  segments = m_tess->edge_segment_data(contour_id, interpolator_id);

  for (const TessellatedPath::segment &S : segments)
    {
      if (S.m_type == TessellatedPath::line_segment)
        {
          m_b->line_to(S.m_end_pt);
        }
      else
        {
          unsigned int max_recustion(5);
          detail::add_arc_as_cubics(max_recustion, m_b, half_tol,
                                    S.m_start_pt, S.m_end_pt, S.m_center,
                                    S.m_radius, S.m_arc_angle.m_begin,
                                    S.m_arc_angle.m_end - S.m_arc_angle.m_begin);
        }
    }
}

////////////////////////////////////
// ShaderFilledPathPrivate methods
ShaderFilledPathPrivate::
ShaderFilledPathPrivate(BuilderPrivate &B):
  m_bbox(B.m_bbox),
  m_allocation(-1),
  m_number_times_atlas_cleared(0)
{
  using namespace fastuidraw;

  /* the fill rule actually does not matter, since ShaderFilledPath
   * constructs its own attribute data.
   */
  finalize_data(PainterEnums::nonzero_fill_rule, B.m_bbox, &B.m_data);
  B.m_data.query(&m_query_data);

  /* Because B may go out of scope, we need to save the GPU data
   * to our own private array.
   */
  m_gpu_data.resize(m_query_data.m_gpu_data.size());
  std::copy(m_query_data.m_gpu_data.begin(), m_query_data.m_gpu_data.end(), m_gpu_data.begin());
  m_query_data.m_gpu_data = make_c_array(m_gpu_data);
}

ShaderFilledPathPrivate::
~ShaderFilledPathPrivate()
{
  if (m_allocation != -1 && m_number_times_atlas_cleared == m_atlas->number_times_cleared())
    {
      m_atlas->deallocate_data(m_allocation, m_gpu_data.size());
    }
}

const PerFillRule&
ShaderFilledPathPrivate::
per_fill_rule(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
              enum fastuidraw::PainterEnums::fill_rule_t fill_rule)
{
  using namespace fastuidraw;

  if (m_atlas != atlas)
    {
      if (m_allocation != -1)
        {
          m_atlas->deallocate_data(m_allocation, m_gpu_data.size());
          m_allocation = -1;
        }
      m_atlas = atlas;
    }

  if (m_allocation == -1 || m_number_times_atlas_cleared != m_atlas->number_times_cleared())
    {
      m_number_times_atlas_cleared = m_atlas->number_times_cleared();
      m_allocation = m_atlas->allocate_data(make_c_array(m_gpu_data));
      update_attribute_data();
    }
  FASTUIDRAWassert(m_allocation != -1);
  return m_per_fill_rule[fill_rule];
}

void
ShaderFilledPathPrivate::
update_attribute_data(void)
{
  using namespace fastuidraw;

  FASTUIDRAWassert(m_allocation != -1);
  for (unsigned int f = 0; f < m_per_fill_rule.size(); ++f)
    {
      m_query_data.set_glyph_attributes(&m_per_fill_rule[f].m_glyph_attribs,
                                        static_cast<enum PainterEnums::fill_rule_t>(f),
                                        m_allocation);
      Glyph::pack_raw(m_per_fill_rule[f].m_glyph_attribs,
                      0, m_per_fill_rule[f].m_attribs,
                      0, m_per_fill_rule[f].m_indices,
                      m_bbox.min_point(), m_bbox.max_point());
    }
}

/////////////////////////////////////////////////
// fastuidraw::ShaderFilledPath::Builder methods
fastuidraw::ShaderFilledPath::Builder::
Builder(void)
{
  m_d = FASTUIDRAWnew BuilderPrivate();
}

fastuidraw::ShaderFilledPath::Builder::
~Builder()
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  FASTUIDRAWdelete(d);
}

void
fastuidraw::ShaderFilledPath::Builder::
move_to(vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.move_to(pt);
  d->m_bbox.union_point(pt);
}

void
fastuidraw::ShaderFilledPath::Builder::
line_to(vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.line_to(pt);
  d->m_bbox.union_point(pt);
}

void
fastuidraw::ShaderFilledPath::Builder::
quadratic_to(vec2 ct, vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.quadratic_to(ct, pt);
  d->m_bbox.union_point(pt);
  d->m_bbox.union_point(ct);
}

void
fastuidraw::ShaderFilledPath::Builder::
add_path(float tol, const Path &path)
{
  AddPath add_path(tol, &path, this);
  add_path.add_to_render_data();
}

////////////////////////////////////////
// fastuidraw::ShaderFilledPath methods
fastuidraw::ShaderFilledPath::
ShaderFilledPath(const Builder &B)
{
  BuilderPrivate *bd;
  bd = static_cast<BuilderPrivate*>(B.m_d);

  m_d = FASTUIDRAWnew ShaderFilledPathPrivate(*bd);
}

fastuidraw::ShaderFilledPath::
~ShaderFilledPath()
{
  ShaderFilledPathPrivate *d;
  d = static_cast<ShaderFilledPathPrivate*>(m_d);
  FASTUIDRAWdelete(d);
}

void
fastuidraw::ShaderFilledPath::
render_data(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
            enum PainterEnums::fill_rule_t fill_rule,
            c_array<const PainterAttribute> *out_attribs,
            c_array<const PainterIndex> *out_indices) const
{
  ShaderFilledPathPrivate *d;
  d = static_cast<ShaderFilledPathPrivate*>(m_d);

  const PerFillRule &F(d->per_fill_rule(atlas, fill_rule));
  *out_attribs = F.m_attribs;
  *out_indices = F.m_indices;
}

enum fastuidraw::glyph_type
fastuidraw::ShaderFilledPath::
render_type(void) const
{
  return GlyphType;
}
<commit_msg>fastuidraw/painter/shader_filled_path: merge arcs that are continuations<commit_after>/*!
 * \file shader_filled_path.cpp
 * \brief file shader_filled_path.cpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#include <vector>
#include <fastuidraw/path.hpp>
#include <fastuidraw/tessellated_path.hpp>
#include <fastuidraw/text/font.hpp>
#include <fastuidraw/text/glyph.hpp>
#include <fastuidraw/text/glyph_render_data_banded_rays.hpp>
#include <fastuidraw/text/glyph_render_data_restricted_rays.hpp>
#include <fastuidraw/painter/shader_filled_path.hpp>
#include "../private/util_private.hpp"
#include "../private/bounding_box.hpp"
#include "../private/bezier_util.hpp"

namespace
{
  /* RestrictedRays, although slower in performance, gives more robust
   * anti-aliasing when zoomed in a great deal than BandedRays.
   */
#if 1
  typedef fastuidraw::GlyphRenderDataRestrictedRays RenderData;
  const enum fastuidraw::glyph_type GlyphType = fastuidraw::restricted_rays_glyph;

  inline
  void
  finalize_data(enum fastuidraw::PainterEnums::fill_rule_t f,
                const fastuidraw::BoundingBox<float> &bbox,
                fastuidraw::GlyphRenderDataRestrictedRays *data)
  {
    data->finalize(f, bbox.as_rect(),
                   4, //aim for 4 curves per box
                   12, //recurse up to 12 times.
                   fastuidraw::vec2(-1.0f, -1.0f));
  }

#else
  typedef fastuidraw::GlyphRenderDataBandedRays RenderData;
  const enum fastuidraw::glyph_type GlyphType = fastuidraw::banded_rays_glyph;

  inline
  void
  finalize_data(enum fastuidraw::PainterEnums::fill_rule_t f,
                const fastuidraw::BoundingBox<float> &bbox,
                fastuidraw::GlyphRenderDataBandedRays *data)
  {
    data->finalize(f, bbox.as_rect());
  }

#endif

  class BuilderPrivate
  {
  public:
    RenderData m_data;
    fastuidraw::BoundingBox<float> m_bbox;
  };

  class AddPath
  {
  public:
    explicit
    AddPath(float tol,
            const fastuidraw::Path *path,
            fastuidraw::ShaderFilledPath::Builder *b):
      m_tol(tol),
      m_b(b),
      m_path(path),
      m_tess(nullptr)
    {}

    void
    add_to_render_data(void);

  private:
    void
    add_contour(unsigned int contour);

    void
    add_interpolator(const fastuidraw::PathContour *contour,
                     unsigned int contour_id, unsigned int interpolator_id);

    void
    add_interpolator_from_tess(unsigned int contour_id, unsigned int interpolator_id);

    float m_tol;
    fastuidraw::ShaderFilledPath::Builder *m_b;
    const fastuidraw::Path *m_path;
    const fastuidraw::TessellatedPath *m_tess;
  };

  class PerFillRule
  {
  public:
    fastuidraw::vecN<fastuidraw::PainterAttribute, 4> m_attribs;
    fastuidraw::vecN<fastuidraw::PainterIndex, 6> m_indices;
    fastuidraw::vecN<fastuidraw::GlyphAttribute, RenderData::glyph_num_attributes> m_glyph_attribs;
  };

  class ShaderFilledPathPrivate
  {
  public:
    explicit
    ShaderFilledPathPrivate(BuilderPrivate &B);

    ~ShaderFilledPathPrivate();

    const PerFillRule&
    per_fill_rule(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
                  enum fastuidraw::PainterEnums::fill_rule_t fill_rule);

  private:
    void
    update_attribute_data(void);

    fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> m_atlas;
    fastuidraw::BoundingBox<float> m_bbox;
    int m_allocation;
    std::vector<fastuidraw::generic_data> m_gpu_data;
    RenderData::query_info m_query_data;

    fastuidraw::vecN<PerFillRule, fastuidraw::PainterEnums::fill_rule_data_count> m_per_fill_rule;
    unsigned int m_number_times_atlas_cleared;
  };
}

////////////////////////////////
// AddPath methods
void
AddPath::
add_to_render_data(void)
{
  for (unsigned int i = 0, endi = m_path->number_contours(); i < endi; ++i)
    {
      add_contour(i);
    }
}

void
AddPath::
add_contour(unsigned int contour_id)
{
  using namespace fastuidraw;

  reference_counted_ptr<const PathContour> contour(m_path->contour(contour_id));
  if (contour->number_interpolators() == 0)
    {
      return;
    }

  m_b->move_to(contour->point(0));
  for (unsigned int i = 0, endi = contour->number_interpolators(); i < endi; ++i)
    {
      add_interpolator(contour.get(), contour_id, i);
    }

  if (!contour->closed())
    {
      m_b->line_to(contour->point(0));
    }
}

void
AddPath::
add_interpolator(const fastuidraw::PathContour *contour,
                 unsigned int contour_id, unsigned int interpolator_id)
{
  using namespace fastuidraw;

  enum return_code R;
  const PathContour::interpolator_base *interpolator(contour->interpolator(interpolator_id).get());

  R = interpolator->add_to_builder(m_b, m_tol);
  if (R == routine_fail)
    {
      add_interpolator_from_tess(contour_id, interpolator_id);
    }
}

void
AddPath::
add_interpolator_from_tess(unsigned int contour_id, unsigned int interpolator_id)
{
  using namespace fastuidraw;

  float half_tol(0.5f * m_tol);
  if (!m_tess)
    {
      m_tess = m_path->tessellation(half_tol).get();
    }

  /* walk through the segments of the named interpolator */
  c_array<const TessellatedPath::segment> segments;
  const TessellatedPath::segment *start_arc(nullptr), *prev_segment(nullptr);

  segments = m_tess->edge_segment_data(contour_id, interpolator_id);
  for (const TessellatedPath::segment &S : segments)
    {
      if (prev_segment && start_arc
	  && (S.m_type == TessellatedPath::line_segment
	      || !S.m_continuation_with_predecessor))
	{
	  unsigned int max_recustion(5);
	  FASTUIDRAWassert(prev_segment->m_type == TessellatedPath::arc_segment);
	  detail::add_arc_as_cubics(max_recustion, m_b, half_tol,
				    start_arc->m_start_pt, prev_segment->m_end_pt,
				    start_arc->m_center, start_arc->m_radius,
				    start_arc->m_arc_angle.m_begin,
				    prev_segment->m_arc_angle.m_end - start_arc->m_arc_angle.m_begin);
	  start_arc = nullptr;
	}

      if (S.m_type == TessellatedPath::line_segment)
        {
	  m_b->line_to(S.m_end_pt);
	  start_arc = nullptr;
        }
      else
        {
	  if (!start_arc)
	    {
	      start_arc = &S;
	    }
        }
      prev_segment = &S;
    }

  if (start_arc)
    {
      unsigned int max_recustion(5);
      FASTUIDRAWassert(prev_segment->m_type == TessellatedPath::arc_segment);
      detail::add_arc_as_cubics(max_recustion, m_b, half_tol,
				start_arc->m_start_pt, prev_segment->m_end_pt,
				start_arc->m_center, start_arc->m_radius,
				start_arc->m_arc_angle.m_begin,
				prev_segment->m_arc_angle.m_end - start_arc->m_arc_angle.m_begin);
    }
}

////////////////////////////////////
// ShaderFilledPathPrivate methods
ShaderFilledPathPrivate::
ShaderFilledPathPrivate(BuilderPrivate &B):
  m_bbox(B.m_bbox),
  m_allocation(-1),
  m_number_times_atlas_cleared(0)
{
  using namespace fastuidraw;

  /* the fill rule actually does not matter, since ShaderFilledPath
   * constructs its own attribute data.
   */
  finalize_data(PainterEnums::nonzero_fill_rule, B.m_bbox, &B.m_data);
  B.m_data.query(&m_query_data);

  /* Because B may go out of scope, we need to save the GPU data
   * to our own private array.
   */
  m_gpu_data.resize(m_query_data.m_gpu_data.size());
  std::copy(m_query_data.m_gpu_data.begin(), m_query_data.m_gpu_data.end(), m_gpu_data.begin());
  m_query_data.m_gpu_data = make_c_array(m_gpu_data);
}

ShaderFilledPathPrivate::
~ShaderFilledPathPrivate()
{
  if (m_allocation != -1 && m_number_times_atlas_cleared == m_atlas->number_times_cleared())
    {
      m_atlas->deallocate_data(m_allocation, m_gpu_data.size());
    }
}

const PerFillRule&
ShaderFilledPathPrivate::
per_fill_rule(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
              enum fastuidraw::PainterEnums::fill_rule_t fill_rule)
{
  using namespace fastuidraw;

  if (m_atlas != atlas)
    {
      if (m_allocation != -1)
        {
          m_atlas->deallocate_data(m_allocation, m_gpu_data.size());
          m_allocation = -1;
        }
      m_atlas = atlas;
    }

  if (m_allocation == -1 || m_number_times_atlas_cleared != m_atlas->number_times_cleared())
    {
      m_number_times_atlas_cleared = m_atlas->number_times_cleared();
      m_allocation = m_atlas->allocate_data(make_c_array(m_gpu_data));
      update_attribute_data();
    }
  FASTUIDRAWassert(m_allocation != -1);
  return m_per_fill_rule[fill_rule];
}

void
ShaderFilledPathPrivate::
update_attribute_data(void)
{
  using namespace fastuidraw;

  FASTUIDRAWassert(m_allocation != -1);
  for (unsigned int f = 0; f < m_per_fill_rule.size(); ++f)
    {
      m_query_data.set_glyph_attributes(&m_per_fill_rule[f].m_glyph_attribs,
                                        static_cast<enum PainterEnums::fill_rule_t>(f),
                                        m_allocation);
      Glyph::pack_raw(m_per_fill_rule[f].m_glyph_attribs,
                      0, m_per_fill_rule[f].m_attribs,
                      0, m_per_fill_rule[f].m_indices,
                      m_bbox.min_point(), m_bbox.max_point());
    }
}

/////////////////////////////////////////////////
// fastuidraw::ShaderFilledPath::Builder methods
fastuidraw::ShaderFilledPath::Builder::
Builder(void)
{
  m_d = FASTUIDRAWnew BuilderPrivate();
}

fastuidraw::ShaderFilledPath::Builder::
~Builder()
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  FASTUIDRAWdelete(d);
}

void
fastuidraw::ShaderFilledPath::Builder::
move_to(vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.move_to(pt);
  d->m_bbox.union_point(pt);
}

void
fastuidraw::ShaderFilledPath::Builder::
line_to(vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.line_to(pt);
  d->m_bbox.union_point(pt);
}

void
fastuidraw::ShaderFilledPath::Builder::
quadratic_to(vec2 ct, vec2 pt)
{
  BuilderPrivate *d;
  d = static_cast<BuilderPrivate*>(m_d);
  d->m_data.quadratic_to(ct, pt);
  d->m_bbox.union_point(pt);
  d->m_bbox.union_point(ct);
}

void
fastuidraw::ShaderFilledPath::Builder::
add_path(float tol, const Path &path)
{
  AddPath add_path(tol, &path, this);
  add_path.add_to_render_data();
}

////////////////////////////////////////
// fastuidraw::ShaderFilledPath methods
fastuidraw::ShaderFilledPath::
ShaderFilledPath(const Builder &B)
{
  BuilderPrivate *bd;
  bd = static_cast<BuilderPrivate*>(B.m_d);

  m_d = FASTUIDRAWnew ShaderFilledPathPrivate(*bd);
}

fastuidraw::ShaderFilledPath::
~ShaderFilledPath()
{
  ShaderFilledPathPrivate *d;
  d = static_cast<ShaderFilledPathPrivate*>(m_d);
  FASTUIDRAWdelete(d);
}

void
fastuidraw::ShaderFilledPath::
render_data(const fastuidraw::reference_counted_ptr<fastuidraw::GlyphAtlas> &atlas,
            enum PainterEnums::fill_rule_t fill_rule,
            c_array<const PainterAttribute> *out_attribs,
            c_array<const PainterIndex> *out_indices) const
{
  ShaderFilledPathPrivate *d;
  d = static_cast<ShaderFilledPathPrivate*>(m_d);

  const PerFillRule &F(d->per_fill_rule(atlas, fill_rule));
  *out_attribs = F.m_attribs;
  *out_indices = F.m_indices;
}

enum fastuidraw::glyph_type
fastuidraw::ShaderFilledPath::
render_type(void) const
{
  return GlyphType;
}
<|endoftext|>


<commit_before>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 **************************************************************************/

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif

#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/PrettyStackTrace.h>

#include "pipe/p_config.h"
#include "util/u_debug.h"

/**
 * Register the engine with oprofile.
 *
 * This allows to see the LLVM IR function names in oprofile output.
 *
 * To actually work LLVM needs to be built with the --with-oprofile configure
 * option.
 *
 * Also a oprofile:oprofile user:group is necessary. Which is not created by
 * default on some distributions.
 */
extern "C" void
lp_register_oprofile_jit_event_listener(LLVMExecutionEngineRef EE)
{
   llvm::unwrap(EE)->RegisterJITEventListener(llvm::createOProfileJITEventListener());
}

extern "C" void
lp_set_target_options(void)
{
#if defined(DEBUG)
#if HAVE_LLVM >= 0x0207
   llvm::JITEmitDebugInfo = true;
#endif
#endif

#if defined(DEBUG) || defined(PROFILE)
   llvm::NoFramePointerElim = true;
#endif

   llvm::NoExcessFPPrecision = false;

   /* XXX: Investigate this */
#if 0
   llvm::UnsafeFPMath = true;
#endif

#if HAVE_LLVM < 0x0209
   /*
    * LLVM will generate MMX instructions for vectors <= 64 bits, leading to
    * innefficient code, and in 32bit systems, to the corruption of the FPU
    * stack given that it expects the user to generate the EMMS instructions.
    *
    * See also:
    * - http://llvm.org/bugs/show_bug.cgi?id=3287
    * - http://l4.me.uk/post/2009/06/07/llvm-wrinkle-3-configuration-what-configuration/
    */
   static boolean first = TRUE;
   if (first) {
      static const char* options[] = {
         "prog",
         "-disable-mmx"
      };
      llvm::cl::ParseCommandLineOptions(2, const_cast<char**>(options));
      first = FALSE;
   }
#endif

   /*
    * By default LLVM adds a signal handler to output a pretty stack trace.
    * This signal handler is never removed, causing problems when unloading the
    * shared object where the gallium driver resides.
    */
   llvm::DisablePrettyStackTrace = true;
}

extern "C" void
lp_func_delete_body(LLVMValueRef FF)
{
   llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
   func->deleteBody();
}

extern "C"
LLVMValueRef
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
                       const char *Name)
{
   return llvm::wrap(llvm::unwrap(B)->CreateLoad(llvm::unwrap(PointerVal), true, Name));
}

<commit_msg>gallivm: Tell LLVM to not assume a 16-byte aligned stack on x86.<commit_after>/**************************************************************************
 *
 * Copyright 2010 VMware, Inc.
 * All Rights Reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sub license, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 * USE OR OTHER DEALINGS IN THE SOFTWARE.
 *
 * The above copyright notice and this permission notice (including the
 * next paragraph) shall be included in all copies or substantial portions
 * of the Software.
 *
 **************************************************************************/

#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif

#ifndef __STDC_CONSTANT_MACROS
#define __STDC_CONSTANT_MACROS
#endif

#include <llvm-c/Core.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm/ExecutionEngine/ExecutionEngine.h>
#include <llvm/ExecutionEngine/JITEventListener.h>
#include <llvm/Support/CommandLine.h>
#include <llvm/Support/PrettyStackTrace.h>

#include "pipe/p_config.h"
#include "util/u_debug.h"

/**
 * Register the engine with oprofile.
 *
 * This allows to see the LLVM IR function names in oprofile output.
 *
 * To actually work LLVM needs to be built with the --with-oprofile configure
 * option.
 *
 * Also a oprofile:oprofile user:group is necessary. Which is not created by
 * default on some distributions.
 */
extern "C" void
lp_register_oprofile_jit_event_listener(LLVMExecutionEngineRef EE)
{
   llvm::unwrap(EE)->RegisterJITEventListener(llvm::createOProfileJITEventListener());
}

extern "C" void
lp_set_target_options(void)
{
#if defined(DEBUG)
#if HAVE_LLVM >= 0x0207
   llvm::JITEmitDebugInfo = true;
#endif
#endif

   /*
    * LLVM revision 123367 switched the default stack alignment to 16 bytes on
    * Linux (and several other Unices in later revisions), to match recent gcc
    * versions.
    *
    * However our drivers can be loaded by old binary applications, still
    * maintaining a 4 bytes stack alignment.  Therefore we must tell LLVM here
    * to only assume a 4 bytes alignment for backwards compatibility.
    */
#if defined(PIPE_ARCH_X86)
   llvm::StackAlignment = 4;
#endif

#if defined(DEBUG) || defined(PROFILE)
   llvm::NoFramePointerElim = true;
#endif

   llvm::NoExcessFPPrecision = false;

   /* XXX: Investigate this */
#if 0
   llvm::UnsafeFPMath = true;
#endif

#if HAVE_LLVM < 0x0209
   /*
    * LLVM will generate MMX instructions for vectors <= 64 bits, leading to
    * innefficient code, and in 32bit systems, to the corruption of the FPU
    * stack given that it expects the user to generate the EMMS instructions.
    *
    * See also:
    * - http://llvm.org/bugs/show_bug.cgi?id=3287
    * - http://l4.me.uk/post/2009/06/07/llvm-wrinkle-3-configuration-what-configuration/
    */
   static boolean first = TRUE;
   if (first) {
      static const char* options[] = {
         "prog",
         "-disable-mmx"
      };
      llvm::cl::ParseCommandLineOptions(2, const_cast<char**>(options));
      first = FALSE;
   }
#endif

   /*
    * By default LLVM adds a signal handler to output a pretty stack trace.
    * This signal handler is never removed, causing problems when unloading the
    * shared object where the gallium driver resides.
    */
   llvm::DisablePrettyStackTrace = true;
}

extern "C" void
lp_func_delete_body(LLVMValueRef FF)
{
   llvm::Function *func = llvm::unwrap<llvm::Function>(FF);
   func->deleteBody();
}

extern "C"
LLVMValueRef
lp_build_load_volatile(LLVMBuilderRef B, LLVMValueRef PointerVal,
                       const char *Name)
{
   return llvm::wrap(llvm::unwrap(B)->CreateLoad(llvm::unwrap(PointerVal), true, Name));
}

<|endoftext|>