<commit_before>// RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -g -o - %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -g -o - -load %llvmshlibdir/PrintFunctionNames%pluginext %s 2>&1 | FileCheck %s

namespace PR16214_1 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
  int i;
};

typedef foo bar;

bar *a;
bar b;
}

namespace PR14467 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

foo *bar(foo *a) {
  foo *b = new foo(*a);
  return b;
}
}

namespace test1 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

extern int bar(foo *a);
int baz(foo *a) {
  return bar(a);
}
}

namespace test2 {
// FIXME: if we were a bit fancier, we could realize that the 'foo' type is only
// required because of the 'bar' type which is not required at all (or might
// only be required to be declared)
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

struct bar {
  foo f;
};

void func() {
  foo *f;
}
}
<commit_msg>DebugInfo: Ensure the ASTConsumer "HandleTagDeclRequireDefinition" callback path is tested.<commit_after>// RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -g -o - %s | FileCheck %s
// RUN: %clang_cc1 -emit-llvm -fno-standalone-debug -g -o - -load %llvmshlibdir/PrintFunctionNames%pluginext %s 2>&1 | FileCheck %s

// CHECK-DAG: [ DW_TAG_structure_type ] [PR16214] [line [[@LINE+1]], {{.*}} [def]
struct PR16214 {
  int i;
};

typedef PR16214 bar;

bar *a;
bar b;

namespace PR14467 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

foo *bar(foo *a) {
  foo *b = new foo(*a);
  return b;
}
}

namespace test1 {
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

extern int bar(foo *a);
int baz(foo *a) {
  return bar(a);
}
}

namespace test2 {
// FIXME: if we were a bit fancier, we could realize that the 'foo' type is only
// required because of the 'bar' type which is not required at all (or might
// only be required to be declared)
// CHECK-DAG: [ DW_TAG_structure_type ] [foo] [line [[@LINE+1]], {{.*}} [def]
struct foo {
};

struct bar {
  foo f;
};

void func() {
  foo *f;
}
}
<|endoftext|>


<commit_before>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <Common/Colorful.hh>
#include <Lex/Lexer.hh>
#include <Object/StringObject.hh>
#include <Core/TadpoleVM.hh>
#include <Compiler/Parser.hh>

namespace Tadpole::Compiler {

GlobalParser::GlobalParser(Core::TadpoleVM& vm, Lex::Lexer& lex) noexcept
  : vm_(vm), lex_(lex) {
}

void GlobalParser::iter_objects(Object::ObjectVisitor&& visitor) {
  // TODO:
}

Object::FunctionObject* GlobalParser::compile() {
  // TODO:
  return nullptr;
}

const ParseRule& GlobalParser::get_rule(Lex::TokenKind kind) const noexcept {
  static const ParseRule _rules[] = {
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(LPAREN, "(")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(RPAREN, ")")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(LBRACE, "{")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(RBRACE, "}")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(COMMA, ",")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(MINUS, "-")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(PLUS, "+")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(SEMI, ";")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(SLASH, "/")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(STAR, "*")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(EQ, "=")

    {nullptr, nullptr, Precedence::NONE}, // TOKEN(IDENTIFIER, "Identifier")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(NUMERIC, "Numeric")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(STRING, "String")

    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(FALSE, "false")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(FN, "fn")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(NIL, "nil")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(TRUE, "true")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(VAR, "var")

    {nullptr, nullptr, Precedence::NONE}, // TOKEN(EOF, "Eof")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(ERR, "Error")
  };

  return _rules[Common::as_type<int>(kind)];
}

void GlobalParser::error_at(const Lex::Token& tok, const str_t& msg) noexcept {
  if (panic_mode_)
    return;
  panic_mode_ = true;

  std::cerr
    << Common::Colorful::fg::red
    << "SyntaxError:" << std::endl
    << "  [LINE: " << tok.lineno() << "] ERROR ";
  if (tok.kind() == Lex::TokenKind::TK_EOF)
    std::cerr << "at end ";
  else if (tok.kind() == Lex::TokenKind::TK_ERR)
    TADPOLE_UNUSED(0);
  else
    std::cerr << "at `" << tok.literal() << "` ";
  std::cerr << ": " << msg << Common::Colorful::reset << std::endl;
}

void GlobalParser::advance() {
  prev_ = curr_;

  for (;;) {
    curr_ = lex_.next_token();
    if (!check(Lex::TokenKind::TK_ERR))
      break;

    error_at_current(curr_.as_string());
  }
}

void GlobalParser::consume(Lex::TokenKind kind, const str_t& msg) {
  if (check(kind))
    advance();
  else
    error_at_current(msg);
}

bool GlobalParser::match(Lex::TokenKind kind) {
  if (check(kind)) {
    advance();
    return true;
  }
  return false;
}

void GlobalParser::init_compiler(FunctionCompiler* compiler, int scope_depth, FunctionType fn_type) {
  Object::StringObject* fn_name{};
  if (fn_type == FunctionType::FUNCTION)
    fn_name = Object::StringObject::create(prev_.as_string());

  compiler->set_compiler(
      curr_compiler_,
      Object::FunctionObject::create(fn_name),
      fn_type,
      scope_depth);
  curr_compiler_ = compiler;

  curr_compiler_->append_local({Lex::Token::make(""), curr_compiler_->scope_depth(), false});
}

Object::FunctionObject* GlobalParser::finish_compiler() {
  emit_return();

  Object::FunctionObject* fn = curr_compiler_->fn();
#if defined(_TADPOLE_DEBUG_VM)
  if (!had_error_)
    curr_chunk()->dis(fn->name_asstr());
#endif

  curr_compiler_ = curr_compiler_->enclosing();
  return fn;
}

void GlobalParser::enter_scope() {
  curr_compiler_->enter_scope();
}

void GlobalParser::leave_scope() {
}

}
<commit_msg>:construction: chore(parser): add leave scope implementation of parser<commit_after>// Copyright (c) 2021 ASMlover. All rights reserved.
//
//  ______             __                  ___
// /\__  _\           /\ \                /\_ \
// \/_/\ \/    __     \_\ \  _____     ___\//\ \      __
//    \ \ \  /'__`\   /'_` \/\ '__`\  / __`\\ \ \   /'__`\
//     \ \ \/\ \L\.\_/\ \L\ \ \ \L\ \/\ \L\ \\_\ \_/\  __/
//      \ \_\ \__/.\_\ \___,_\ \ ,__/\ \____//\____\ \____\
//       \/_/\/__/\/_/\/__,_ /\ \ \/  \/___/ \/____/\/____/
//                             \ \_\
//                              \/_/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
//  * Redistributions of source code must retain the above copyright
//    notice, this list ofconditions and the following disclaimer.
//
//  * Redistributions in binary form must reproduce the above copyright
//    notice, this list of conditions and the following disclaimer in
//    the documentation and/or other materialsprovided with the
//    distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
#include <iostream>
#include <Common/Colorful.hh>
#include <Lex/Lexer.hh>
#include <Object/StringObject.hh>
#include <Core/TadpoleVM.hh>
#include <Compiler/Parser.hh>

namespace Tadpole::Compiler {

GlobalParser::GlobalParser(Core::TadpoleVM& vm, Lex::Lexer& lex) noexcept
  : vm_(vm), lex_(lex) {
}

void GlobalParser::iter_objects(Object::ObjectVisitor&& visitor) {
  // TODO:
}

Object::FunctionObject* GlobalParser::compile() {
  // TODO:
  return nullptr;
}

const ParseRule& GlobalParser::get_rule(Lex::TokenKind kind) const noexcept {
  static const ParseRule _rules[] = {
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(LPAREN, "(")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(RPAREN, ")")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(LBRACE, "{")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(RBRACE, "}")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(COMMA, ",")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(MINUS, "-")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(PLUS, "+")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(SEMI, ";")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(SLASH, "/")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(STAR, "*")
    {nullptr, nullptr, Precedence::NONE}, // PUNCTUATOR(EQ, "=")

    {nullptr, nullptr, Precedence::NONE}, // TOKEN(IDENTIFIER, "Identifier")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(NUMERIC, "Numeric")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(STRING, "String")

    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(FALSE, "false")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(FN, "fn")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(NIL, "nil")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(TRUE, "true")
    {nullptr, nullptr, Precedence::NONE}, // KEYWORD(VAR, "var")

    {nullptr, nullptr, Precedence::NONE}, // TOKEN(EOF, "Eof")
    {nullptr, nullptr, Precedence::NONE}, // TOKEN(ERR, "Error")
  };

  return _rules[Common::as_type<int>(kind)];
}

void GlobalParser::error_at(const Lex::Token& tok, const str_t& msg) noexcept {
  if (panic_mode_)
    return;
  panic_mode_ = true;

  std::cerr
    << Common::Colorful::fg::red
    << "SyntaxError:" << std::endl
    << "  [LINE: " << tok.lineno() << "] ERROR ";
  if (tok.kind() == Lex::TokenKind::TK_EOF)
    std::cerr << "at end ";
  else if (tok.kind() == Lex::TokenKind::TK_ERR)
    TADPOLE_UNUSED(0);
  else
    std::cerr << "at `" << tok.literal() << "` ";
  std::cerr << ": " << msg << Common::Colorful::reset << std::endl;
}

void GlobalParser::advance() {
  prev_ = curr_;

  for (;;) {
    curr_ = lex_.next_token();
    if (!check(Lex::TokenKind::TK_ERR))
      break;

    error_at_current(curr_.as_string());
  }
}

void GlobalParser::consume(Lex::TokenKind kind, const str_t& msg) {
  if (check(kind))
    advance();
  else
    error_at_current(msg);
}

bool GlobalParser::match(Lex::TokenKind kind) {
  if (check(kind)) {
    advance();
    return true;
  }
  return false;
}

void GlobalParser::init_compiler(FunctionCompiler* compiler, int scope_depth, FunctionType fn_type) {
  Object::StringObject* fn_name{};
  if (fn_type == FunctionType::FUNCTION)
    fn_name = Object::StringObject::create(prev_.as_string());

  compiler->set_compiler(
      curr_compiler_,
      Object::FunctionObject::create(fn_name),
      fn_type,
      scope_depth);
  curr_compiler_ = compiler;

  curr_compiler_->append_local({Lex::Token::make(""), curr_compiler_->scope_depth(), false});
}

Object::FunctionObject* GlobalParser::finish_compiler() {
  emit_return();

  Object::FunctionObject* fn = curr_compiler_->fn();
#if defined(_TADPOLE_DEBUG_VM)
  if (!had_error_)
    curr_chunk()->dis(fn->name_asstr());
#endif

  curr_compiler_ = curr_compiler_->enclosing();
  return fn;
}

void GlobalParser::enter_scope() {
  curr_compiler_->enter_scope();
}

void GlobalParser::leave_scope() {
  curr_compiler_->leave_scope([this](const LocalVar& var) {
        emit_byte(var.is_upvalue ? Core::Code::CLOSE_UPVALUE : Core::Code::POP);
      });
}

}
<|endoftext|>


<commit_before>//===- LoopVR.cpp - Value Range analysis driven by loop information -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// FIXME: What does this do?
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loopvr"
#include "llvm/Analysis/LoopVR.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

char LoopVR::ID = 0;
static RegisterPass<LoopVR> X("loopvr", "Loop Value Ranges", false, true);

/// getRange - determine the range for a particular SCEV within a given Loop
ConstantRange LoopVR::getRange(SCEVHandle S, Loop *L, ScalarEvolution &SE) {
  SCEVHandle T = SE.getBackedgeTakenCount(L);
  if (isa<SCEVCouldNotCompute>(T))
    return ConstantRange(cast<IntegerType>(S->getType())->getBitWidth(), true);

  T = SE.getTruncateOrZeroExtend(T, S->getType());
  return getRange(S, T, SE);
}

/// getRange - determine the range for a particular SCEV with a given trip count
ConstantRange LoopVR::getRange(SCEVHandle S, SCEVHandle T, ScalarEvolution &SE){

  if (SCEVConstant *C = dyn_cast<SCEVConstant>(S))
    return ConstantRange(C->getValue()->getValue());

  ConstantRange FullSet(cast<IntegerType>(S->getType())->getBitWidth(), true);

  // {x,+,y,+,...z}. We detect overflow by checking the size of the set after
  // summing the upper and lower.
  if (SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
    ConstantRange X = getRange(Add->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;
    for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(Add->getOperand(i), T, SE);
      if (Y.isFullSet()) return FullSet;

      APInt Spread_X = X.getSetSize(), Spread_Y = Y.getSetSize();
      APInt NewLower = X.getLower() + Y.getLower();
      APInt NewUpper = X.getUpper() + Y.getUpper() - 1;
      if (NewLower == NewUpper)
        return FullSet;

      X = ConstantRange(NewLower, NewUpper);
      if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y))
        return FullSet; // we've wrapped, therefore, full set.
    }
    return X;
  }

  // {x,*,y,*,...,z}. In order to detect overflow, we use k*bitwidth where
  // k is the number of terms being multiplied.
  if (SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(S)) {
    ConstantRange X = getRange(Mul->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    const IntegerType *Ty = IntegerType::get(X.getBitWidth());
    const IntegerType *ExTy = IntegerType::get(X.getBitWidth() *
                                               Mul->getNumOperands());
    ConstantRange XExt = X.zeroExtend(ExTy->getBitWidth());

    for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(Mul->getOperand(i), T, SE);
      if (Y.isFullSet()) return FullSet;

      ConstantRange YExt = Y.zeroExtend(ExTy->getBitWidth());
      XExt = ConstantRange(XExt.getLower() * YExt.getLower(),
                           ((XExt.getUpper()-1) * (YExt.getUpper()-1)) + 1);
    }
    return XExt.truncate(Ty->getBitWidth());
  }

  // X smax Y smax ... Z is: range(smax(X_smin, Y_smin, ..., Z_smin),
  //                               smax(X_smax, Y_smax, ..., Z_smax))
  // It doesn't matter if one of the SCEVs has FullSet because we're taking
  // a maximum of the minimums across all of them.
  if (SCEVSMaxExpr *SMax = dyn_cast<SCEVSMaxExpr>(S)) {
    ConstantRange X = getRange(SMax->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    APInt smin = X.getSignedMin(), smax = X.getSignedMax();
    for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(SMax->getOperand(i), T, SE);
      smin = APIntOps::smax(smin, Y.getSignedMin());
      smax = APIntOps::smax(smax, Y.getSignedMax());
    }
    if (smax + 1 == smin) return FullSet;
    return ConstantRange(smin, smax + 1);
  }

  // X umax Y umax ... Z is: range(umax(X_umin, Y_umin, ..., Z_umin),
  //                               umax(X_umax, Y_umax, ..., Z_umax))
  // It doesn't matter if one of the SCEVs has FullSet because we're taking
  // a maximum of the minimums across all of them.
  if (SCEVUMaxExpr *UMax = dyn_cast<SCEVUMaxExpr>(S)) {
    ConstantRange X = getRange(UMax->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    APInt umin = X.getUnsignedMin(), umax = X.getUnsignedMax();
    for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(UMax->getOperand(i), T, SE);
      umin = APIntOps::umax(umin, Y.getUnsignedMin());
      umax = APIntOps::umax(umax, Y.getUnsignedMax());
    }
    if (umax + 1 == umin) return FullSet;
    return ConstantRange(umin, umax + 1);
  }

  // L udiv R. Luckily, there's only ever 2 sides to a udiv.
  if (SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
    ConstantRange L = getRange(UDiv->getLHS(), T, SE);
    ConstantRange R = getRange(UDiv->getRHS(), T, SE);
    if (L.isFullSet() && R.isFullSet()) return FullSet;

    if (R.getUnsignedMax() == 0) {
      // RHS must be single-element zero. Return an empty set.
      return ConstantRange(R.getBitWidth(), false);
    }

    APInt Lower = L.getUnsignedMin().udiv(R.getUnsignedMax());

    APInt Upper;

    if (R.getUnsignedMin() == 0) {
      // Just because it contains zero, doesn't mean it will also contain one.
      // Use maximalIntersectWith to get the right behaviour.
      ConstantRange NotZero(APInt(L.getBitWidth(), 1),
                            APInt::getNullValue(L.getBitWidth()));
      R = R.maximalIntersectWith(NotZero);
    }

    // But, the maximal intersection might still include zero. If it does, then
    // we know it also included one.
    if (R.contains(APInt::getNullValue(L.getBitWidth())))
      Upper = L.getUnsignedMax();
    else
      Upper = L.getUnsignedMax().udiv(R.getUnsignedMin());

    return ConstantRange(Lower, Upper);
  }

  // ConstantRange already implements the cast operators.

  if (SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, ZExt->getOperand()->getType());
    ConstantRange X = getRange(ZExt->getOperand(), T, SE);
    return X.zeroExtend(cast<IntegerType>(ZExt->getType())->getBitWidth());
  }

  if (SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, SExt->getOperand()->getType());
    ConstantRange X = getRange(SExt->getOperand(), T, SE);
    return X.signExtend(cast<IntegerType>(SExt->getType())->getBitWidth());
  }

  if (SCEVTruncateExpr *Trunc = dyn_cast<SCEVTruncateExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, Trunc->getOperand()->getType());
    ConstantRange X = getRange(Trunc->getOperand(), T, SE);
    if (X.isFullSet()) return FullSet;
    return X.truncate(cast<IntegerType>(Trunc->getType())->getBitWidth());
  }

  if (SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
    SCEVConstant *Trip = dyn_cast<SCEVConstant>(T);
    if (!Trip) return FullSet;

    if (AddRec->isAffine()) {
      SCEVHandle StartHandle = AddRec->getStart();
      SCEVHandle StepHandle = AddRec->getOperand(1);

      SCEVConstant *Step = dyn_cast<SCEVConstant>(StepHandle);
      if (!Step) return FullSet;

      uint32_t ExWidth = 2 * Trip->getValue()->getBitWidth();
      APInt TripExt = Trip->getValue()->getValue(); TripExt.zext(ExWidth);
      APInt StepExt = Step->getValue()->getValue(); StepExt.zext(ExWidth);
      if ((TripExt * StepExt).ugt(APInt::getLowBitsSet(ExWidth, ExWidth >> 1)))
        return FullSet;

      SCEVHandle EndHandle = SE.getAddExpr(StartHandle,
                                           SE.getMulExpr(T, StepHandle));
      SCEVConstant *Start = dyn_cast<SCEVConstant>(StartHandle);
      SCEVConstant *End = dyn_cast<SCEVConstant>(EndHandle);
      if (!Start || !End) return FullSet;

      const APInt &StartInt = Start->getValue()->getValue();
      const APInt &EndInt = End->getValue()->getValue();
      const APInt &StepInt = Step->getValue()->getValue();

      if (StepInt.isNegative()) {
        if (EndInt == StartInt + 1) return FullSet;
        return ConstantRange(EndInt, StartInt + 1);
      } else {
        if (StartInt == EndInt + 1) return FullSet;
        return ConstantRange(StartInt, EndInt + 1);
      }
    }
  }

  // TODO: non-affine addrec, udiv, SCEVUnknown (narrowed from elsewhere)?

  return FullSet;
}

bool LoopVR::runOnFunction(Function &F) { Map.clear(); return false; }

void LoopVR::print(std::ostream &os, const Module *) const {
  raw_os_ostream OS(os);
  for (std::map<Value *, ConstantRange *>::const_iterator I = Map.begin(),
       E = Map.end(); I != E; ++I) {
    OS << *I->first << ": " << *I->second << '\n';
  }
}

void LoopVR::releaseMemory() {
  for (std::map<Value *, ConstantRange *>::iterator I = Map.begin(),
       E = Map.end(); I != E; ++I) {
    delete I->second;
  }

  Map.clear();
}

ConstantRange LoopVR::compute(Value *V) {
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return ConstantRange(CI->getValue());

  Instruction *I = dyn_cast<Instruction>(V);
  if (!I)
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  LoopInfo &LI = getAnalysis<LoopInfo>();

  Loop *L = LI.getLoopFor(I->getParent());
  if (!L || L->isLoopInvariant(I))
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  ScalarEvolution &SE = getAnalysis<ScalarEvolution>();

  SCEVHandle S = SE.getSCEV(I);
  if (isa<SCEVUnknown>(S) || isa<SCEVCouldNotCompute>(S))
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  return ConstantRange(getRange(S, L, SE));
}

ConstantRange LoopVR::get(Value *V) {
  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I == Map.end()) {
    ConstantRange *CR = new ConstantRange(compute(V));
    Map[V] = CR;
    return *CR;
  }

  return *I->second;
}

void LoopVR::remove(Value *V) {
  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I != Map.end()) {
    delete I->second;
    Map.erase(I);
  }
}

void LoopVR::narrow(Value *V, const ConstantRange &CR) {
  if (CR.isFullSet()) return;

  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I == Map.end())
    Map[V] = new ConstantRange(CR);
  else
    Map[V] = new ConstantRange(Map[V]->maximalIntersectWith(CR));
}
<commit_msg>More const qualifiers.<commit_after>//===- LoopVR.cpp - Value Range analysis driven by loop information -------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// FIXME: What does this do?
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "loopvr"
#include "llvm/Analysis/LoopVR.h"
#include "llvm/Constants.h"
#include "llvm/Instructions.h"
#include "llvm/Analysis/ScalarEvolutionExpressions.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;

char LoopVR::ID = 0;
static RegisterPass<LoopVR> X("loopvr", "Loop Value Ranges", false, true);

/// getRange - determine the range for a particular SCEV within a given Loop
ConstantRange LoopVR::getRange(SCEVHandle S, Loop *L, ScalarEvolution &SE) {
  SCEVHandle T = SE.getBackedgeTakenCount(L);
  if (isa<SCEVCouldNotCompute>(T))
    return ConstantRange(cast<IntegerType>(S->getType())->getBitWidth(), true);

  T = SE.getTruncateOrZeroExtend(T, S->getType());
  return getRange(S, T, SE);
}

/// getRange - determine the range for a particular SCEV with a given trip count
ConstantRange LoopVR::getRange(SCEVHandle S, SCEVHandle T, ScalarEvolution &SE){

  if (const SCEVConstant *C = dyn_cast<SCEVConstant>(S))
    return ConstantRange(C->getValue()->getValue());

  ConstantRange FullSet(cast<IntegerType>(S->getType())->getBitWidth(), true);

  // {x,+,y,+,...z}. We detect overflow by checking the size of the set after
  // summing the upper and lower.
  if (const SCEVAddExpr *Add = dyn_cast<SCEVAddExpr>(S)) {
    ConstantRange X = getRange(Add->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;
    for (unsigned i = 1, e = Add->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(Add->getOperand(i), T, SE);
      if (Y.isFullSet()) return FullSet;

      APInt Spread_X = X.getSetSize(), Spread_Y = Y.getSetSize();
      APInt NewLower = X.getLower() + Y.getLower();
      APInt NewUpper = X.getUpper() + Y.getUpper() - 1;
      if (NewLower == NewUpper)
        return FullSet;

      X = ConstantRange(NewLower, NewUpper);
      if (X.getSetSize().ult(Spread_X) || X.getSetSize().ult(Spread_Y))
        return FullSet; // we've wrapped, therefore, full set.
    }
    return X;
  }

  // {x,*,y,*,...,z}. In order to detect overflow, we use k*bitwidth where
  // k is the number of terms being multiplied.
  if (const SCEVMulExpr *Mul = dyn_cast<SCEVMulExpr>(S)) {
    ConstantRange X = getRange(Mul->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    const IntegerType *Ty = IntegerType::get(X.getBitWidth());
    const IntegerType *ExTy = IntegerType::get(X.getBitWidth() *
                                               Mul->getNumOperands());
    ConstantRange XExt = X.zeroExtend(ExTy->getBitWidth());

    for (unsigned i = 1, e = Mul->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(Mul->getOperand(i), T, SE);
      if (Y.isFullSet()) return FullSet;

      ConstantRange YExt = Y.zeroExtend(ExTy->getBitWidth());
      XExt = ConstantRange(XExt.getLower() * YExt.getLower(),
                           ((XExt.getUpper()-1) * (YExt.getUpper()-1)) + 1);
    }
    return XExt.truncate(Ty->getBitWidth());
  }

  // X smax Y smax ... Z is: range(smax(X_smin, Y_smin, ..., Z_smin),
  //                               smax(X_smax, Y_smax, ..., Z_smax))
  // It doesn't matter if one of the SCEVs has FullSet because we're taking
  // a maximum of the minimums across all of them.
  if (const SCEVSMaxExpr *SMax = dyn_cast<SCEVSMaxExpr>(S)) {
    ConstantRange X = getRange(SMax->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    APInt smin = X.getSignedMin(), smax = X.getSignedMax();
    for (unsigned i = 1, e = SMax->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(SMax->getOperand(i), T, SE);
      smin = APIntOps::smax(smin, Y.getSignedMin());
      smax = APIntOps::smax(smax, Y.getSignedMax());
    }
    if (smax + 1 == smin) return FullSet;
    return ConstantRange(smin, smax + 1);
  }

  // X umax Y umax ... Z is: range(umax(X_umin, Y_umin, ..., Z_umin),
  //                               umax(X_umax, Y_umax, ..., Z_umax))
  // It doesn't matter if one of the SCEVs has FullSet because we're taking
  // a maximum of the minimums across all of them.
  if (const SCEVUMaxExpr *UMax = dyn_cast<SCEVUMaxExpr>(S)) {
    ConstantRange X = getRange(UMax->getOperand(0), T, SE);
    if (X.isFullSet()) return FullSet;

    APInt umin = X.getUnsignedMin(), umax = X.getUnsignedMax();
    for (unsigned i = 1, e = UMax->getNumOperands(); i != e; ++i) {
      ConstantRange Y = getRange(UMax->getOperand(i), T, SE);
      umin = APIntOps::umax(umin, Y.getUnsignedMin());
      umax = APIntOps::umax(umax, Y.getUnsignedMax());
    }
    if (umax + 1 == umin) return FullSet;
    return ConstantRange(umin, umax + 1);
  }

  // L udiv R. Luckily, there's only ever 2 sides to a udiv.
  if (const SCEVUDivExpr *UDiv = dyn_cast<SCEVUDivExpr>(S)) {
    ConstantRange L = getRange(UDiv->getLHS(), T, SE);
    ConstantRange R = getRange(UDiv->getRHS(), T, SE);
    if (L.isFullSet() && R.isFullSet()) return FullSet;

    if (R.getUnsignedMax() == 0) {
      // RHS must be single-element zero. Return an empty set.
      return ConstantRange(R.getBitWidth(), false);
    }

    APInt Lower = L.getUnsignedMin().udiv(R.getUnsignedMax());

    APInt Upper;

    if (R.getUnsignedMin() == 0) {
      // Just because it contains zero, doesn't mean it will also contain one.
      // Use maximalIntersectWith to get the right behaviour.
      ConstantRange NotZero(APInt(L.getBitWidth(), 1),
                            APInt::getNullValue(L.getBitWidth()));
      R = R.maximalIntersectWith(NotZero);
    }

    // But, the maximal intersection might still include zero. If it does, then
    // we know it also included one.
    if (R.contains(APInt::getNullValue(L.getBitWidth())))
      Upper = L.getUnsignedMax();
    else
      Upper = L.getUnsignedMax().udiv(R.getUnsignedMin());

    return ConstantRange(Lower, Upper);
  }

  // ConstantRange already implements the cast operators.

  if (const SCEVZeroExtendExpr *ZExt = dyn_cast<SCEVZeroExtendExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, ZExt->getOperand()->getType());
    ConstantRange X = getRange(ZExt->getOperand(), T, SE);
    return X.zeroExtend(cast<IntegerType>(ZExt->getType())->getBitWidth());
  }

  if (const SCEVSignExtendExpr *SExt = dyn_cast<SCEVSignExtendExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, SExt->getOperand()->getType());
    ConstantRange X = getRange(SExt->getOperand(), T, SE);
    return X.signExtend(cast<IntegerType>(SExt->getType())->getBitWidth());
  }

  if (const SCEVTruncateExpr *Trunc = dyn_cast<SCEVTruncateExpr>(S)) {
    T = SE.getTruncateOrZeroExtend(T, Trunc->getOperand()->getType());
    ConstantRange X = getRange(Trunc->getOperand(), T, SE);
    if (X.isFullSet()) return FullSet;
    return X.truncate(cast<IntegerType>(Trunc->getType())->getBitWidth());
  }

  if (const SCEVAddRecExpr *AddRec = dyn_cast<SCEVAddRecExpr>(S)) {
    const SCEVConstant *Trip = dyn_cast<SCEVConstant>(T);
    if (!Trip) return FullSet;

    if (AddRec->isAffine()) {
      SCEVHandle StartHandle = AddRec->getStart();
      SCEVHandle StepHandle = AddRec->getOperand(1);

      const SCEVConstant *Step = dyn_cast<SCEVConstant>(StepHandle);
      if (!Step) return FullSet;

      uint32_t ExWidth = 2 * Trip->getValue()->getBitWidth();
      APInt TripExt = Trip->getValue()->getValue(); TripExt.zext(ExWidth);
      APInt StepExt = Step->getValue()->getValue(); StepExt.zext(ExWidth);
      if ((TripExt * StepExt).ugt(APInt::getLowBitsSet(ExWidth, ExWidth >> 1)))
        return FullSet;

      SCEVHandle EndHandle = SE.getAddExpr(StartHandle,
                                           SE.getMulExpr(T, StepHandle));
      const SCEVConstant *Start = dyn_cast<SCEVConstant>(StartHandle);
      const SCEVConstant *End = dyn_cast<SCEVConstant>(EndHandle);
      if (!Start || !End) return FullSet;

      const APInt &StartInt = Start->getValue()->getValue();
      const APInt &EndInt = End->getValue()->getValue();
      const APInt &StepInt = Step->getValue()->getValue();

      if (StepInt.isNegative()) {
        if (EndInt == StartInt + 1) return FullSet;
        return ConstantRange(EndInt, StartInt + 1);
      } else {
        if (StartInt == EndInt + 1) return FullSet;
        return ConstantRange(StartInt, EndInt + 1);
      }
    }
  }

  // TODO: non-affine addrec, udiv, SCEVUnknown (narrowed from elsewhere)?

  return FullSet;
}

bool LoopVR::runOnFunction(Function &F) { Map.clear(); return false; }

void LoopVR::print(std::ostream &os, const Module *) const {
  raw_os_ostream OS(os);
  for (std::map<Value *, ConstantRange *>::const_iterator I = Map.begin(),
       E = Map.end(); I != E; ++I) {
    OS << *I->first << ": " << *I->second << '\n';
  }
}

void LoopVR::releaseMemory() {
  for (std::map<Value *, ConstantRange *>::iterator I = Map.begin(),
       E = Map.end(); I != E; ++I) {
    delete I->second;
  }

  Map.clear();
}

ConstantRange LoopVR::compute(Value *V) {
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return ConstantRange(CI->getValue());

  Instruction *I = dyn_cast<Instruction>(V);
  if (!I)
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  LoopInfo &LI = getAnalysis<LoopInfo>();

  Loop *L = LI.getLoopFor(I->getParent());
  if (!L || L->isLoopInvariant(I))
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  ScalarEvolution &SE = getAnalysis<ScalarEvolution>();

  SCEVHandle S = SE.getSCEV(I);
  if (isa<SCEVUnknown>(S) || isa<SCEVCouldNotCompute>(S))
    return ConstantRange(cast<IntegerType>(V->getType())->getBitWidth(), false);

  return ConstantRange(getRange(S, L, SE));
}

ConstantRange LoopVR::get(Value *V) {
  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I == Map.end()) {
    ConstantRange *CR = new ConstantRange(compute(V));
    Map[V] = CR;
    return *CR;
  }

  return *I->second;
}

void LoopVR::remove(Value *V) {
  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I != Map.end()) {
    delete I->second;
    Map.erase(I);
  }
}

void LoopVR::narrow(Value *V, const ConstantRange &CR) {
  if (CR.isFullSet()) return;

  std::map<Value *, ConstantRange *>::iterator I = Map.find(V);
  if (I == Map.end())
    Map[V] = new ConstantRange(CR);
  else
    Map[V] = new ConstantRange(Map[V]->maximalIntersectWith(CR));
}
<|endoftext|>


<commit_before>// Copyright (C) 2010 - 2013 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2003 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

//***  In this file I have put "//+++" in all places where something has to be added
//***  if a new scan item is introduced.

#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QLayout>
#include <QtGui/QToolTip>
#include <QtGui/QWhatsThis>
#include <QtGui/QComboBox>
#include <QtGui/QLineEdit>
#include <QtGui/QGridLayout>
#include <QtGui/QHBoxLayout>

#include <QtGui/QInputDialog>

#include "copasi.h"

#include "ScanWidget.h"
#include "scan/CScanTask.h"
#include "scan/CScanProblem.h"
#include "scan/CScanMethod.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "report/CCopasiRootContainer.h"

#include "CQTaskHeaderWidget.h"
#include "CQTaskBtnWidget.h"
#include "CQSimpleSelectionTree.h"
#include "CCopasiSelectionDialog.h"

#include "report/CKeyFactory.h"
#include "qtUtilities.h"
#include "CScanContainerWidget.h"
#include "utilities/CopasiTime.h"

//+++
//#include "CScanWidgetBreak.h"
#include "CScanWidgetRandom.h"
#include "CScanWidgetRepeat.h"
#include "CScanWidgetScan.h"
#include "CScanWidgetTask.h"

ScanWidget::ScanWidget(QWidget* parent, const char* name, Qt::WFlags f)
  : TaskWidget(parent, name, f)
{
  if (!name)
    setObjectName("ScanWidget");

  setWindowTitle(trUtf8("ScanWidget"));
  ScanWidgetLayout = new QGridLayout(this);
  ScanWidgetLayout->setMargin(11);
  ScanWidgetLayout->setSpacing(6);
  ScanWidgetLayout->setObjectName("ScanWidgetLayout");

  mpHeaderWidget->setTaskName("Parameter Scan");

  ScanWidgetLayout->addWidget(mpHeaderWidget, 0, 0);

  mpBtnWidget->verticalLayout->removeItem(mpBtnWidget->verticalSpacer);
  ScanWidgetLayout->addWidget(mpBtnWidget, 3, 0);

  //*****************

  QHBoxLayout* tmpLayout = new QHBoxLayout();

  QSpacerItem* tmpSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
  tmpLayout->addItem(tmpSpacer);

  QLabel* tmpLabel = new QLabel(this);
  tmpLabel->setText("New scan item: ");
  tmpLayout->addWidget(tmpLabel);

  comboType = new QComboBox(this);
  //+++
  comboType->insertItem(0, "Scan");
  comboType->insertItem(0, "Repeat");
  comboType->insertItem(0, "Random distribution");
  tmpLayout->addWidget(comboType);

  QSpacerItem *mpSpacer = new QSpacerItem(20, 20, QSizePolicy::Maximum, QSizePolicy::Minimum);
  tmpLayout->addItem(mpSpacer);

  buttonNewItem = new QPushButton(this);
  buttonNewItem->setObjectName("buttonNewItem");
  buttonNewItem->setText("Create");
  //ScanWidgetLayout->addWidget(buttonNewItem, 1, 2);
  tmpLayout->addWidget(buttonNewItem);

  ScanWidgetLayout->addLayout(tmpLayout, 1, 0);

  //*****************************

  scrollview = new CScanContainerWidget(this);
  ScanWidgetLayout->addWidget(scrollview, 2, 0);

  // tab order
  /*setTabOrder(taskName, sExecutable);
  setTabOrder(sExecutable, steadyState);*/

  connect(buttonNewItem, SIGNAL(clicked()), this, SLOT(slotAddItem()));
}

ScanWidget::~ScanWidget()
{}

bool ScanWidget::runTask()
{
  if (!commonBeforeRunTask()) return false;

  bool success = true;

  if (!commonRunTask()) success = false;

  return success;
}

bool ScanWidget::loadTask()
{
  loadCommon();

  CScanTask* scanTask =
    dynamic_cast< CScanTask * >(CCopasiRootContainer::getKeyFactory()->get(mKey));

  if (!scanTask) return false;

  CScanProblem *scanProblem = dynamic_cast<CScanProblem *>(scanTask->getProblem());

  if (!scanProblem) return false;

  scrollview->clearWidgetList();

  //std::vector<QWidget*> & widgetList = scrollview->getWidgetList();

  //+++
  CScanWidgetScan* tmp1;
  CScanWidgetRepeat* tmp2;
  CScanWidgetRandom* tmp3;
  //CScanWidgetBreak* tmp4;

  // the scan items
  assert(CCopasiRootContainer::getDatamodelList()->size() > 0);
  //CCopasiDataModel* pDataModel = (*CCopasiRootContainer::getDatamodelList())[0];
  //assert(pDataModel != NULL);
  size_t i, imax = scanProblem->getNumberOfScanItems();

  for (i = 0; i < imax; ++i)
    {
      void * pTmp;

      if (!(pTmp = scanProblem->getScanItem(i)->getValue("Type").pVOID)) return false;

      CScanProblem::Type type = *(CScanProblem::Type*)pTmp;

      switch (type)
        {
            //+++
          case CScanProblem::SCAN_LINEAR:
            tmp1 = new CScanWidgetScan(scrollview);
            tmp1->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp1);
            break;

          case CScanProblem::SCAN_REPEAT:
            tmp2 = new CScanWidgetRepeat(scrollview);
            tmp2->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp2);
            break;

          case CScanProblem::SCAN_RANDOM:
            tmp3 = new CScanWidgetRandom(scrollview);
            tmp3->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp3);
            break;

          default:
            break;
        }
    }

  // the widget for the subtask
  CScanWidgetTask* tmpT = new CScanWidgetTask(scrollview);
  tmpT->load(scanProblem);
  scrollview->addWidget(tmpT, false); //false: no control buttons (up/down/del)

  mChanged = false;

  return true;
}

bool ScanWidget::slotAddItem()
{
  int totalRows = -1;
  //+++
  CScanWidgetScan* tmp1;
  CScanWidgetRepeat* tmp2;
  CScanWidgetRandom* tmp3;
  //CScanWidgetBreak* tmp4;

  int intType = comboType->currentIndex();
  CScanProblem::Type type;

  switch (intType)
    {
      case 0:
        type = CScanProblem::SCAN_LINEAR;
        break;

      case 1:
        type = CScanProblem::SCAN_REPEAT;
        break;

      case 2:
        type = CScanProblem::SCAN_RANDOM;
        break;

      default:
        type = CScanProblem::SCAN_LINEAR;
        break;
    }

  switch (type)
    {
      case CScanProblem::SCAN_REPEAT:
      {
        tmp2 = new CScanWidgetRepeat(scrollview);

        //create item to get the default values
        CCopasiParameterGroup* pItem = CScanProblem::createScanItem(type, 10);
        tmp2->load(pItem);
        pdelete(pItem);

        scrollview->insertWidget(tmp2);
        totalRows = scrollview->rowCount();
        tmp2->lineEditNumber->setFocus();
      }
      break;

      case CScanProblem::SCAN_LINEAR:
      {
        CQSimpleSelectionTree::ObjectClasses Classes = CQSimpleSelectionTree::InitialTime |
            CQSimpleSelectionTree::Parameters;

        std::vector< const CCopasiObject * > Selection = CCopasiSelectionDialog::getObjectVector(this, Classes);

        // create scan widgets as many as the number of selected objects
        std::vector< const CCopasiObject * >::iterator it = Selection.begin();
        std::vector< const CCopasiObject * >::iterator end = Selection.end();

        for (; it != end; ++it)
          {
            tmp1 = new CScanWidgetScan(scrollview);
            tmp1->initFromObject(*it);
            scrollview->insertWidget(tmp1);
            totalRows = scrollview->rowCount();
            tmp1->lineEditMin->setFocus();
          }

        break;
      }

      case CScanProblem::SCAN_RANDOM:
      {
        CQSimpleSelectionTree::ObjectClasses Classes = CQSimpleSelectionTree::InitialTime |
            CQSimpleSelectionTree::Parameters;

        std::vector< const CCopasiObject * > Selection = CCopasiSelectionDialog::getObjectVector(this, Classes);

        // create scan widgets as many as the number of selected objects
        std::vector< const CCopasiObject * >::iterator it = Selection.begin();
        std::vector< const CCopasiObject * >::iterator end = Selection.end();

        for (; it != end; ++it)
          {
            tmp3 = new CScanWidgetRandom(scrollview);
            tmp3->initFromObject(*it);
            scrollview->insertWidget(tmp3);
            totalRows = scrollview->rowCount();
            tmp3->lineEditMin->setFocus();
          }

        break;
      }

      default:
        break;
    }

  return true;
}

bool ScanWidget::saveTask()
{
  saveCommon();

  CScanTask* scanTask =
    dynamic_cast< CScanTask * >(CCopasiRootContainer::getKeyFactory()->get(mKey));

  if (!scanTask) return false;

  CScanProblem *scanProblem = dynamic_cast<CScanProblem *>(scanTask->getProblem());

  if (!scanProblem) return false;

  const std::vector< QWidget * > & widgetList = scrollview->getWidgetList();

  size_t newSize = widgetList.size() - 1; // The last widget is reserved for the subtask.
  size_t oldSize = scanProblem->getNumberOfScanItems();

  size_t i, imax = std::min(newSize, oldSize);

  mChanged = false;

  for (i = 0; i < imax; ++i)
    {
      QWidget * pWidget = widgetList[i];

      if (pWidget->objectName() == "CScanWidgetScan")
        {
          mChanged |= static_cast< CScanWidgetScan * >(pWidget)->save(scanProblem->getScanItem(i));
        }
      else if (pWidget->objectName() == "CScanWidgetRandom")
        {
          mChanged |= static_cast< CScanWidgetRandom * >(pWidget)->save(scanProblem->getScanItem(i));
        }
      else if (pWidget->objectName() == "CScanWidgetRepeat")
        {
          mChanged |= static_cast< CScanWidgetRepeat * >(pWidget)->save(scanProblem->getScanItem(i));
        }
    }

  for (; i < newSize; ++i)
    {
      mChanged = true;
      QWidget * pWidget = widgetList[i];
      CCopasiParameterGroup * pItem = scanProblem->addScanItem(CScanProblem::SCAN_LINEAR);

      if (pWidget->objectName() == "CScanWidgetScan")
        {
          static_cast< CScanWidgetScan * >(pWidget)->save(pItem);
        }
      else if (pWidget->objectName() == "CScanWidgetRandom")
        {
          static_cast< CScanWidgetRandom * >(pWidget)->save(pItem);
        }
      else if (pWidget->objectName() == "CScanWidgetRepeat")
        {
          static_cast< CScanWidgetRepeat * >(pWidget)->save(pItem);
        }
    }

  for (; i < oldSize; ++i)
    {
      mChanged = true;
      scanProblem->removeScanItem(newSize);
    }

  // the subtask
  const CScanWidgetTask * tmpT = dynamic_cast<CScanWidgetTask*>(widgetList[newSize]);

  if (tmpT != NULL)
    {
      mChanged |= tmpT->save(scanProblem);
    }

  // :TODO Bug 322: This should only be called when actual changes have been saved.
  // However we do not check whether the scan item are mChanged we delete all
  // and create them new.
  if (mChanged)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      mChanged = false;
    }

  return true;
}
<commit_msg>Bug 2000. The combo box items were inserted into the front instead of appended to the list creating an incorrect order.<commit_after>// Copyright (C) 2010 - 2014 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., University of Heidelberg, and The University
// of Manchester.
// All rights reserved.

// Copyright (C) 2008 - 2009 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc., EML Research, gGmbH, University of Heidelberg,
// and The University of Manchester.
// All rights reserved.

// Copyright (C) 2003 - 2007 by Pedro Mendes, Virginia Tech Intellectual
// Properties, Inc. and EML Research, gGmbH.
// All rights reserved.

//***  In this file I have put "//+++" in all places where something has to be added
//***  if a new scan item is introduced.

#include <QtGui/QLabel>
#include <QtGui/QPushButton>
#include <QtGui/QLayout>
#include <QtGui/QToolTip>
#include <QtGui/QWhatsThis>
#include <QtGui/QComboBox>
#include <QtGui/QLineEdit>
#include <QtGui/QGridLayout>
#include <QtGui/QHBoxLayout>

#include <QtGui/QInputDialog>

#include "copasi.h"

#include "ScanWidget.h"
#include "scan/CScanTask.h"
#include "scan/CScanProblem.h"
#include "scan/CScanMethod.h"
#include "CopasiDataModel/CCopasiDataModel.h"
#include "report/CCopasiRootContainer.h"

#include "CQTaskHeaderWidget.h"
#include "CQTaskBtnWidget.h"
#include "CQSimpleSelectionTree.h"
#include "CCopasiSelectionDialog.h"

#include "report/CKeyFactory.h"
#include "qtUtilities.h"
#include "CScanContainerWidget.h"
#include "utilities/CopasiTime.h"

//+++
//#include "CScanWidgetBreak.h"
#include "CScanWidgetRandom.h"
#include "CScanWidgetRepeat.h"
#include "CScanWidgetScan.h"
#include "CScanWidgetTask.h"

ScanWidget::ScanWidget(QWidget* parent, const char* name, Qt::WFlags f)
  : TaskWidget(parent, name, f)
{
  if (!name)
    setObjectName("ScanWidget");

  setWindowTitle(trUtf8("ScanWidget"));
  ScanWidgetLayout = new QGridLayout(this);
  ScanWidgetLayout->setMargin(11);
  ScanWidgetLayout->setSpacing(6);
  ScanWidgetLayout->setObjectName("ScanWidgetLayout");

  mpHeaderWidget->setTaskName("Parameter Scan");

  ScanWidgetLayout->addWidget(mpHeaderWidget, 0, 0);

  mpBtnWidget->verticalLayout->removeItem(mpBtnWidget->verticalSpacer);
  ScanWidgetLayout->addWidget(mpBtnWidget, 3, 0);

  //*****************

  QHBoxLayout* tmpLayout = new QHBoxLayout();

  QSpacerItem* tmpSpacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Minimum);
  tmpLayout->addItem(tmpSpacer);

  QLabel* tmpLabel = new QLabel(this);
  tmpLabel->setText("New scan item: ");
  tmpLayout->addWidget(tmpLabel);

  comboType = new QComboBox(this);
  //+++
  comboType->addItem("Scan");
  comboType->addItem("Repeat");
  comboType->addItem("Random distribution");
  tmpLayout->addWidget(comboType);

  QSpacerItem *mpSpacer = new QSpacerItem(20, 20, QSizePolicy::Maximum, QSizePolicy::Minimum);
  tmpLayout->addItem(mpSpacer);

  buttonNewItem = new QPushButton(this);
  buttonNewItem->setObjectName("buttonNewItem");
  buttonNewItem->setText("Create");
  //ScanWidgetLayout->addWidget(buttonNewItem, 1, 2);
  tmpLayout->addWidget(buttonNewItem);

  ScanWidgetLayout->addLayout(tmpLayout, 1, 0);

  //*****************************

  scrollview = new CScanContainerWidget(this);
  ScanWidgetLayout->addWidget(scrollview, 2, 0);

  // tab order
  /*setTabOrder(taskName, sExecutable);
  setTabOrder(sExecutable, steadyState);*/

  connect(buttonNewItem, SIGNAL(clicked()), this, SLOT(slotAddItem()));
}

ScanWidget::~ScanWidget()
{}

bool ScanWidget::runTask()
{
  if (!commonBeforeRunTask()) return false;

  bool success = true;

  if (!commonRunTask()) success = false;

  return success;
}

bool ScanWidget::loadTask()
{
  loadCommon();

  CScanTask* scanTask =
    dynamic_cast< CScanTask * >(CCopasiRootContainer::getKeyFactory()->get(mKey));

  if (!scanTask) return false;

  CScanProblem *scanProblem = dynamic_cast<CScanProblem *>(scanTask->getProblem());

  if (!scanProblem) return false;

  scrollview->clearWidgetList();

  //std::vector<QWidget*> & widgetList = scrollview->getWidgetList();

  //+++
  CScanWidgetScan* tmp1;
  CScanWidgetRepeat* tmp2;
  CScanWidgetRandom* tmp3;
  //CScanWidgetBreak* tmp4;

  // the scan items
  assert(CCopasiRootContainer::getDatamodelList()->size() > 0);
  //CCopasiDataModel* pDataModel = (*CCopasiRootContainer::getDatamodelList())[0];
  //assert(pDataModel != NULL);
  size_t i, imax = scanProblem->getNumberOfScanItems();

  for (i = 0; i < imax; ++i)
    {
      void * pTmp;

      if (!(pTmp = scanProblem->getScanItem(i)->getValue("Type").pVOID)) return false;

      CScanProblem::Type type = *(CScanProblem::Type*)pTmp;

      switch (type)
        {
            //+++
          case CScanProblem::SCAN_LINEAR:
            tmp1 = new CScanWidgetScan(scrollview);
            tmp1->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp1);
            break;

          case CScanProblem::SCAN_REPEAT:
            tmp2 = new CScanWidgetRepeat(scrollview);
            tmp2->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp2);
            break;

          case CScanProblem::SCAN_RANDOM:
            tmp3 = new CScanWidgetRandom(scrollview);
            tmp3->load(scanProblem->getScanItem(i));
            scrollview->addWidget(tmp3);
            break;

          default:
            break;
        }
    }

  // the widget for the subtask
  CScanWidgetTask* tmpT = new CScanWidgetTask(scrollview);
  tmpT->load(scanProblem);
  scrollview->addWidget(tmpT, false); //false: no control buttons (up/down/del)

  mChanged = false;

  return true;
}

bool ScanWidget::slotAddItem()
{
  int totalRows = -1;
  //+++
  CScanWidgetScan* tmp1;
  CScanWidgetRepeat* tmp2;
  CScanWidgetRandom* tmp3;
  //CScanWidgetBreak* tmp4;

  int intType = comboType->currentIndex();
  CScanProblem::Type type;

  switch (intType)
    {
      case 0:
        type = CScanProblem::SCAN_LINEAR;
        break;

      case 1:
        type = CScanProblem::SCAN_REPEAT;
        break;

      case 2:
        type = CScanProblem::SCAN_RANDOM;
        break;

      default:
        type = CScanProblem::SCAN_LINEAR;
        break;
    }

  switch (type)
    {
      case CScanProblem::SCAN_REPEAT:
      {
        tmp2 = new CScanWidgetRepeat(scrollview);

        //create item to get the default values
        CCopasiParameterGroup* pItem = CScanProblem::createScanItem(type, 10);
        tmp2->load(pItem);
        pdelete(pItem);

        scrollview->insertWidget(tmp2);
        totalRows = scrollview->rowCount();
        tmp2->lineEditNumber->setFocus();
      }
      break;

      case CScanProblem::SCAN_LINEAR:
      {
        CQSimpleSelectionTree::ObjectClasses Classes = CQSimpleSelectionTree::InitialTime |
            CQSimpleSelectionTree::Parameters;

        std::vector< const CCopasiObject * > Selection = CCopasiSelectionDialog::getObjectVector(this, Classes);

        // create scan widgets as many as the number of selected objects
        std::vector< const CCopasiObject * >::iterator it = Selection.begin();
        std::vector< const CCopasiObject * >::iterator end = Selection.end();

        for (; it != end; ++it)
          {
            tmp1 = new CScanWidgetScan(scrollview);
            tmp1->initFromObject(*it);
            scrollview->insertWidget(tmp1);
            totalRows = scrollview->rowCount();
            tmp1->lineEditMin->setFocus();
          }

        break;
      }

      case CScanProblem::SCAN_RANDOM:
      {
        CQSimpleSelectionTree::ObjectClasses Classes = CQSimpleSelectionTree::InitialTime |
            CQSimpleSelectionTree::Parameters;

        std::vector< const CCopasiObject * > Selection = CCopasiSelectionDialog::getObjectVector(this, Classes);

        // create scan widgets as many as the number of selected objects
        std::vector< const CCopasiObject * >::iterator it = Selection.begin();
        std::vector< const CCopasiObject * >::iterator end = Selection.end();

        for (; it != end; ++it)
          {
            tmp3 = new CScanWidgetRandom(scrollview);
            tmp3->initFromObject(*it);
            scrollview->insertWidget(tmp3);
            totalRows = scrollview->rowCount();
            tmp3->lineEditMin->setFocus();
          }

        break;
      }

      default:
        break;
    }

  return true;
}

bool ScanWidget::saveTask()
{
  saveCommon();

  CScanTask* scanTask =
    dynamic_cast< CScanTask * >(CCopasiRootContainer::getKeyFactory()->get(mKey));

  if (!scanTask) return false;

  CScanProblem *scanProblem = dynamic_cast<CScanProblem *>(scanTask->getProblem());

  if (!scanProblem) return false;

  const std::vector< QWidget * > & widgetList = scrollview->getWidgetList();

  size_t newSize = widgetList.size() - 1; // The last widget is reserved for the subtask.
  size_t oldSize = scanProblem->getNumberOfScanItems();

  size_t i, imax = std::min(newSize, oldSize);

  mChanged = false;

  for (i = 0; i < imax; ++i)
    {
      QWidget * pWidget = widgetList[i];

      if (pWidget->objectName() == "CScanWidgetScan")
        {
          mChanged |= static_cast< CScanWidgetScan * >(pWidget)->save(scanProblem->getScanItem(i));
        }
      else if (pWidget->objectName() == "CScanWidgetRandom")
        {
          mChanged |= static_cast< CScanWidgetRandom * >(pWidget)->save(scanProblem->getScanItem(i));
        }
      else if (pWidget->objectName() == "CScanWidgetRepeat")
        {
          mChanged |= static_cast< CScanWidgetRepeat * >(pWidget)->save(scanProblem->getScanItem(i));
        }
    }

  for (; i < newSize; ++i)
    {
      mChanged = true;
      QWidget * pWidget = widgetList[i];
      CCopasiParameterGroup * pItem = scanProblem->addScanItem(CScanProblem::SCAN_LINEAR);

      if (pWidget->objectName() == "CScanWidgetScan")
        {
          static_cast< CScanWidgetScan * >(pWidget)->save(pItem);
        }
      else if (pWidget->objectName() == "CScanWidgetRandom")
        {
          static_cast< CScanWidgetRandom * >(pWidget)->save(pItem);
        }
      else if (pWidget->objectName() == "CScanWidgetRepeat")
        {
          static_cast< CScanWidgetRepeat * >(pWidget)->save(pItem);
        }
    }

  for (; i < oldSize; ++i)
    {
      mChanged = true;
      scanProblem->removeScanItem(newSize);
    }

  // the subtask
  const CScanWidgetTask * tmpT = dynamic_cast<CScanWidgetTask*>(widgetList[newSize]);

  if (tmpT != NULL)
    {
      mChanged |= tmpT->save(scanProblem);
    }

  // :TODO Bug 322: This should only be called when actual changes have been saved.
  // However we do not check whether the scan item are mChanged we delete all
  // and create them new.
  if (mChanged)
    {
      if (mpDataModel != NULL)
        {
          mpDataModel->changed();
        }

      mChanged = false;
    }

  return true;
}
<|endoftext|>


<commit_before>//===--- SourceLoc.cpp - SourceLoc and SourceRange implementations --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"

using namespace swift;

void SourceManager::verifyAllBuffers() const {
  llvm::PrettyStackTraceString backtrace{
    "Checking that all source buffers are still valid"
  };

  // FIXME: This depends on the buffer IDs chosen by llvm::SourceMgr.
  LLVM_ATTRIBUTE_USED static char arbitraryTotal = 0;
  for (unsigned i = 1, e = LLVMSourceMgr.getNumBuffers(); i <= e; ++i) {
    auto *buffer = LLVMSourceMgr.getMemoryBuffer(i);
    if (buffer->getBufferSize() == 0)
      continue;
    arbitraryTotal += buffer->getBufferStart()[0];
    arbitraryTotal += buffer->getBufferEnd()[-1];
  }
}

SourceLoc SourceManager::getCodeCompletionLoc() const {
  if (CodeCompletionBufferID == 0U)
    return SourceLoc();

  return getLocForBufferStart(CodeCompletionBufferID)
      .getAdvancedLoc(CodeCompletionOffset);
}

StringRef SourceManager::getDisplayNameForLoc(SourceLoc Loc) const {
  // Respect #line first
  if (auto VFile = getVirtualFile(Loc))
    return VFile->Name;

  // Next, try the stat cache
  auto Ident = getIdentifierForBuffer(findBufferContainingLoc(Loc));
  auto found = StatusCache.find(Ident);
  if (found != StatusCache.end()) {
    return found->second.getName();
  }

  // Populate the cache with a (virtual) stat.
  if (auto Status = FileSystem->status(Ident)) {
    return (StatusCache[Ident] = Status.get()).getName();
  }

  // Finally, fall back to the buffer identifier.
  return Ident;
}

unsigned
SourceManager::addNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
  assert(Buffer);
  StringRef BufIdentifier = Buffer->getBufferIdentifier();
  auto ID = LLVMSourceMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
  BufIdentIDMap[BufIdentifier] = ID;
  return ID;
}

unsigned SourceManager::addMemBufferCopy(llvm::MemoryBuffer *Buffer) {
  return addMemBufferCopy(Buffer->getBuffer(), Buffer->getBufferIdentifier());
}

unsigned SourceManager::addMemBufferCopy(StringRef InputData,
                                         StringRef BufIdentifier) {
  auto Buffer = std::unique_ptr<llvm::MemoryBuffer>(
      llvm::MemoryBuffer::getMemBufferCopy(InputData, BufIdentifier));
  return addNewSourceBuffer(std::move(Buffer));
}

bool SourceManager::openVirtualFile(SourceLoc loc, StringRef name,
                                    int lineOffset) {
  CharSourceRange fullRange = getRangeForBuffer(findBufferContainingLoc(loc));
  SourceLoc end;

  auto nextRangeIter = VirtualFiles.upper_bound(loc.Value.getPointer());
  if (nextRangeIter != VirtualFiles.end() &&
      fullRange.contains(nextRangeIter->second.Range.getStart())) {
    const VirtualFile &existingFile = nextRangeIter->second;
    if (existingFile.Range.getStart() == loc) {
      assert(existingFile.Name == name);
      assert(existingFile.LineOffset == lineOffset);
      return false;
    }
    assert(!existingFile.Range.contains(loc) &&
           "must close current open file first");
    end = nextRangeIter->second.Range.getStart();
  } else {
    end = fullRange.getEnd();
  }

  CharSourceRange range = CharSourceRange(*this, loc, end);
  VirtualFiles[end.Value.getPointer()] = {range, name.str(), lineOffset};
  CachedVFile = {nullptr, nullptr};
  return true;
}

void SourceManager::closeVirtualFile(SourceLoc end) {
  auto *virtualFile = const_cast<VirtualFile *>(getVirtualFile(end));
  if (!virtualFile) {
#ifndef NDEBUG
    unsigned bufferID = findBufferContainingLoc(end);
    CharSourceRange fullRange = getRangeForBuffer(bufferID);
    assert((fullRange.getByteLength() == 0 ||
            getVirtualFile(end.getAdvancedLoc(-1))) &&
           "no open virtual file for this location");
    assert(fullRange.getEnd() == end);
#endif
    return;
  }
  CachedVFile = {nullptr, nullptr};

  CharSourceRange oldRange = virtualFile->Range;
  virtualFile->Range = CharSourceRange(*this, virtualFile->Range.getStart(),
                                       end);
  VirtualFiles[end.Value.getPointer()] = std::move(*virtualFile);

  bool existed = VirtualFiles.erase(oldRange.getEnd().Value.getPointer());
  assert(existed);
  (void)existed;
}

const SourceManager::VirtualFile *
SourceManager::getVirtualFile(SourceLoc Loc) const {
  const char *p = Loc.Value.getPointer();

  if (CachedVFile.first == p)
    return CachedVFile.second;

  // Returns the first element that is >p.
  auto VFileIt = VirtualFiles.upper_bound(p);
  if (VFileIt != VirtualFiles.end() && VFileIt->second.Range.contains(Loc)) {
    CachedVFile = { p, &VFileIt->second };
    return CachedVFile.second;
  }

  return nullptr;
}

Optional<unsigned>
SourceManager::getIDForBufferIdentifier(StringRef BufIdentifier) const {
  auto It = BufIdentIDMap.find(BufIdentifier);
  if (It == BufIdentIDMap.end())
    return None;
  return It->second;
}

StringRef SourceManager::getIdentifierForBuffer(unsigned bufferID) const {
  auto *buffer = LLVMSourceMgr.getMemoryBuffer(bufferID);
  assert(buffer && "invalid buffer ID");
  return buffer->getBufferIdentifier();
}

CharSourceRange SourceManager::getRangeForBuffer(unsigned bufferID) const {
  auto *buffer = LLVMSourceMgr.getMemoryBuffer(bufferID);
  SourceLoc start{llvm::SMLoc::getFromPointer(buffer->getBufferStart())};
  return CharSourceRange(start, buffer->getBufferSize());
}

unsigned SourceManager::getLocOffsetInBuffer(SourceLoc Loc,
                                             unsigned BufferID) const {
  assert(Loc.isValid() && "location should be valid");
  auto *Buffer = LLVMSourceMgr.getMemoryBuffer(BufferID);
  assert(Loc.Value.getPointer() >= Buffer->getBuffer().begin() &&
         Loc.Value.getPointer() <= Buffer->getBuffer().end() &&
         "Location is not from the specified buffer");
  return Loc.Value.getPointer() - Buffer->getBuffer().begin();
}

unsigned SourceManager::getByteDistance(SourceLoc Start, SourceLoc End) const {
  assert(Start.isValid() && "start location should be valid");
  assert(End.isValid() && "end location should be valid");
#ifndef NDEBUG
  unsigned BufferID = findBufferContainingLoc(Start);
  auto *Buffer = LLVMSourceMgr.getMemoryBuffer(BufferID);
  assert(End.Value.getPointer() >= Buffer->getBuffer().begin() &&
         End.Value.getPointer() <= Buffer->getBuffer().end() &&
         "End location is not from the same buffer");
#endif
  // When we have a rope buffer, could be implemented in terms of
  // getLocOffsetInBuffer().
  return End.Value.getPointer() - Start.Value.getPointer();
}

StringRef SourceManager::getEntireTextForBuffer(unsigned BufferID) const {
  return LLVMSourceMgr.getMemoryBuffer(BufferID)->getBuffer();
}

StringRef SourceManager::extractText(CharSourceRange Range,
                                     Optional<unsigned> BufferID) const {
  assert(Range.isValid() && "range should be valid");

  if (!BufferID)
    BufferID = findBufferContainingLoc(Range.getStart());
  StringRef Buffer = LLVMSourceMgr.getMemoryBuffer(*BufferID)->getBuffer();
  return Buffer.substr(getLocOffsetInBuffer(Range.getStart(), *BufferID),
                       Range.getByteLength());
}

Optional<unsigned>
SourceManager::findBufferContainingLocInternal(SourceLoc Loc) const {
  assert(Loc.isValid());
  // Search the buffers back-to front, so later alias buffers are
  // visited first.
  auto less_equal = std::less_equal<const char *>();
  for (unsigned i = LLVMSourceMgr.getNumBuffers(), e = 1; i >= e; --i) {
    auto Buf = LLVMSourceMgr.getMemoryBuffer(i);
    if (less_equal(Buf->getBufferStart(), Loc.Value.getPointer()) &&
        // Use <= here so that a pointer to the null at the end of the buffer
        // is included as part of the buffer.
        less_equal(Loc.Value.getPointer(), Buf->getBufferEnd()))
      return i;
  }
  return None;
}

unsigned SourceManager::findBufferContainingLoc(SourceLoc Loc) const {
  auto Id = findBufferContainingLocInternal(Loc);
  if (Id.hasValue())
    return *Id;
  llvm_unreachable("no buffer containing location found");
}

bool SourceManager::isOwning(SourceLoc Loc) const {
  return findBufferContainingLocInternal(Loc).hasValue();
}

void SourceRange::widen(SourceRange Other) {
  if (Other.Start.Value.getPointer() < Start.Value.getPointer())
    Start = Other.Start;
  if (Other.End.Value.getPointer() > End.Value.getPointer())
    End = Other.End;
}

void SourceLoc::printLineAndColumn(raw_ostream &OS, const SourceManager &SM,
                                   unsigned BufferID) const {
  if (isInvalid()) {
    OS << "<invalid loc>";
    return;
  }

  auto LineAndCol = SM.getPresumedLineAndColumnForLoc(*this, BufferID);
  OS << "line:" << LineAndCol.first << ':' << LineAndCol.second;
}

void SourceLoc::print(raw_ostream &OS, const SourceManager &SM,
                      unsigned &LastBufferID) const {
  if (isInvalid()) {
    OS << "<invalid loc>";
    return;
  }

  unsigned BufferID = SM.findBufferContainingLoc(*this);
  if (BufferID != LastBufferID) {
    OS << SM.getIdentifierForBuffer(BufferID);
    LastBufferID = BufferID;
  } else {
    OS << "line";
  }

  auto LineAndCol = SM.getPresumedLineAndColumnForLoc(*this, BufferID);
  OS << ':' << LineAndCol.first << ':' << LineAndCol.second;
}

void SourceLoc::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

void SourceRange::print(raw_ostream &OS, const SourceManager &SM,
                        unsigned &LastBufferID, bool PrintText) const {
  // FIXME: CharSourceRange is a half-open character-based range, while
  // SourceRange is a closed token-based range, so this conversion omits the
  // last token in the range. Unfortunately, we can't actually get to the end
  // of the token without using the Lex library, which would be a layering
  // violation. This is still better than nothing.
  CharSourceRange(SM, Start, End).print(OS, SM, LastBufferID, PrintText);
}

void SourceRange::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

CharSourceRange::CharSourceRange(const SourceManager &SM, SourceLoc Start,
                                 SourceLoc End)
    : Start(Start) {
  assert(Start.isValid() == End.isValid() &&
         "Start and end should either both be valid or both be invalid!");
  if (Start.isValid())
    ByteLength = SM.getByteDistance(Start, End);
}

void CharSourceRange::print(raw_ostream &OS, const SourceManager &SM,
                            unsigned &LastBufferID, bool PrintText) const {
  OS << '[';
  Start.print(OS, SM, LastBufferID);
  OS << " - ";
  getEnd().print(OS, SM, LastBufferID);
  OS << ']';

  if (Start.isInvalid() || getEnd().isInvalid())
    return;

  if (PrintText) {
    OS << " RangeText=\"" << SM.extractText(*this) << '"';
  }
}

void CharSourceRange::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

llvm::Optional<unsigned>
SourceManager::resolveOffsetForEndOfLine(unsigned BufferId,
                                         unsigned Line) const {
  return resolveFromLineCol(BufferId, Line, ~0u);
}

llvm::Optional<unsigned>
SourceManager::getLineLength(unsigned BufferId, unsigned Line) const {
  auto BegOffset = resolveFromLineCol(BufferId, Line, 0);
  auto EndOffset = resolveFromLineCol(BufferId, Line, ~0u);
  if (BegOffset && EndOffset) {
     return EndOffset.getValue() - BegOffset.getValue();
  }
  return None;
}

llvm::Optional<unsigned> SourceManager::resolveFromLineCol(unsigned BufferId,
                                                           unsigned Line,
                                                           unsigned Col) const {
  if (Line == 0) {
    return None;
  }
  const bool LineEnd = Col == ~0u;
  auto InputBuf = getLLVMSourceMgr().getMemoryBuffer(BufferId);
  const char *Ptr = InputBuf->getBufferStart();
  const char *End = InputBuf->getBufferEnd();
  const char *LineStart = Ptr;
  --Line;
  for (; Line && (Ptr < End); ++Ptr) {
    if (*Ptr == '\n') {
      --Line;
      LineStart = Ptr+1;
    }
  }
  if (Line != 0) {
    return None;
  }
  Ptr = LineStart;
  if (Col == 0)   {
      return Ptr - InputBuf->getBufferStart();
  }
  // The <= here is to allow for non-inclusive range end positions at EOF
  for (; ; ++Ptr) {
    --Col;
    if (Col == 0)
      return Ptr - InputBuf->getBufferStart();
    if (*Ptr == '\n' || Ptr == End) {
      if (LineEnd) {
        return Ptr - InputBuf->getBufferStart();
      } else {
        break;
      }
    }
  }
  return None;
}

unsigned SourceManager::getExternalSourceBufferId(StringRef Path) {
  auto It = BufIdentIDMap.find(Path);
  if (It != BufIdentIDMap.end()) {
    return It->getSecond();
  }
  unsigned Id = 0u;
  auto InputFileOrErr = swift::vfs::getFileOrSTDIN(*getFileSystem(), Path);
  if (InputFileOrErr) {
    // This assertion ensures we can look up from the map in the future when
    // using the same Path.
    assert(InputFileOrErr.get()->getBufferIdentifier() == Path);
    Id = addNewSourceBuffer(std::move(InputFileOrErr.get()));
  }
  return Id;
}

SourceLoc
SourceManager::getLocFromExternalSource(StringRef Path, unsigned Line,
                                        unsigned Col) {
  auto BufferId = getExternalSourceBufferId(Path);
  if (BufferId == 0u)
    return SourceLoc();
  auto Offset = resolveFromLineCol(BufferId, Line, Col);
  if (!Offset.hasValue())
    return SourceLoc();
  return getLocForOffset(BufferId, *Offset);
}
<commit_msg>[SourceManager] Use llvm::SourceMgr::FindLocForLineAndColumn()<commit_after>//===--- SourceLoc.cpp - SourceLoc and SourceRange implementations --------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/Basic/SourceLoc.h"
#include "swift/Basic/SourceManager.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/raw_ostream.h"

using namespace swift;

void SourceManager::verifyAllBuffers() const {
  llvm::PrettyStackTraceString backtrace{
    "Checking that all source buffers are still valid"
  };

  // FIXME: This depends on the buffer IDs chosen by llvm::SourceMgr.
  LLVM_ATTRIBUTE_USED static char arbitraryTotal = 0;
  for (unsigned i = 1, e = LLVMSourceMgr.getNumBuffers(); i <= e; ++i) {
    auto *buffer = LLVMSourceMgr.getMemoryBuffer(i);
    if (buffer->getBufferSize() == 0)
      continue;
    arbitraryTotal += buffer->getBufferStart()[0];
    arbitraryTotal += buffer->getBufferEnd()[-1];
  }
}

SourceLoc SourceManager::getCodeCompletionLoc() const {
  if (CodeCompletionBufferID == 0U)
    return SourceLoc();

  return getLocForBufferStart(CodeCompletionBufferID)
      .getAdvancedLoc(CodeCompletionOffset);
}

StringRef SourceManager::getDisplayNameForLoc(SourceLoc Loc) const {
  // Respect #line first
  if (auto VFile = getVirtualFile(Loc))
    return VFile->Name;

  // Next, try the stat cache
  auto Ident = getIdentifierForBuffer(findBufferContainingLoc(Loc));
  auto found = StatusCache.find(Ident);
  if (found != StatusCache.end()) {
    return found->second.getName();
  }

  // Populate the cache with a (virtual) stat.
  if (auto Status = FileSystem->status(Ident)) {
    return (StatusCache[Ident] = Status.get()).getName();
  }

  // Finally, fall back to the buffer identifier.
  return Ident;
}

unsigned
SourceManager::addNewSourceBuffer(std::unique_ptr<llvm::MemoryBuffer> Buffer) {
  assert(Buffer);
  StringRef BufIdentifier = Buffer->getBufferIdentifier();
  auto ID = LLVMSourceMgr.AddNewSourceBuffer(std::move(Buffer), llvm::SMLoc());
  BufIdentIDMap[BufIdentifier] = ID;
  return ID;
}

unsigned SourceManager::addMemBufferCopy(llvm::MemoryBuffer *Buffer) {
  return addMemBufferCopy(Buffer->getBuffer(), Buffer->getBufferIdentifier());
}

unsigned SourceManager::addMemBufferCopy(StringRef InputData,
                                         StringRef BufIdentifier) {
  auto Buffer = std::unique_ptr<llvm::MemoryBuffer>(
      llvm::MemoryBuffer::getMemBufferCopy(InputData, BufIdentifier));
  return addNewSourceBuffer(std::move(Buffer));
}

bool SourceManager::openVirtualFile(SourceLoc loc, StringRef name,
                                    int lineOffset) {
  CharSourceRange fullRange = getRangeForBuffer(findBufferContainingLoc(loc));
  SourceLoc end;

  auto nextRangeIter = VirtualFiles.upper_bound(loc.Value.getPointer());
  if (nextRangeIter != VirtualFiles.end() &&
      fullRange.contains(nextRangeIter->second.Range.getStart())) {
    const VirtualFile &existingFile = nextRangeIter->second;
    if (existingFile.Range.getStart() == loc) {
      assert(existingFile.Name == name);
      assert(existingFile.LineOffset == lineOffset);
      return false;
    }
    assert(!existingFile.Range.contains(loc) &&
           "must close current open file first");
    end = nextRangeIter->second.Range.getStart();
  } else {
    end = fullRange.getEnd();
  }

  CharSourceRange range = CharSourceRange(*this, loc, end);
  VirtualFiles[end.Value.getPointer()] = {range, name.str(), lineOffset};
  CachedVFile = {nullptr, nullptr};
  return true;
}

void SourceManager::closeVirtualFile(SourceLoc end) {
  auto *virtualFile = const_cast<VirtualFile *>(getVirtualFile(end));
  if (!virtualFile) {
#ifndef NDEBUG
    unsigned bufferID = findBufferContainingLoc(end);
    CharSourceRange fullRange = getRangeForBuffer(bufferID);
    assert((fullRange.getByteLength() == 0 ||
            getVirtualFile(end.getAdvancedLoc(-1))) &&
           "no open virtual file for this location");
    assert(fullRange.getEnd() == end);
#endif
    return;
  }
  CachedVFile = {nullptr, nullptr};

  CharSourceRange oldRange = virtualFile->Range;
  virtualFile->Range = CharSourceRange(*this, virtualFile->Range.getStart(),
                                       end);
  VirtualFiles[end.Value.getPointer()] = std::move(*virtualFile);

  bool existed = VirtualFiles.erase(oldRange.getEnd().Value.getPointer());
  assert(existed);
  (void)existed;
}

const SourceManager::VirtualFile *
SourceManager::getVirtualFile(SourceLoc Loc) const {
  const char *p = Loc.Value.getPointer();

  if (CachedVFile.first == p)
    return CachedVFile.second;

  // Returns the first element that is >p.
  auto VFileIt = VirtualFiles.upper_bound(p);
  if (VFileIt != VirtualFiles.end() && VFileIt->second.Range.contains(Loc)) {
    CachedVFile = { p, &VFileIt->second };
    return CachedVFile.second;
  }

  return nullptr;
}

Optional<unsigned>
SourceManager::getIDForBufferIdentifier(StringRef BufIdentifier) const {
  auto It = BufIdentIDMap.find(BufIdentifier);
  if (It == BufIdentIDMap.end())
    return None;
  return It->second;
}

StringRef SourceManager::getIdentifierForBuffer(unsigned bufferID) const {
  auto *buffer = LLVMSourceMgr.getMemoryBuffer(bufferID);
  assert(buffer && "invalid buffer ID");
  return buffer->getBufferIdentifier();
}

CharSourceRange SourceManager::getRangeForBuffer(unsigned bufferID) const {
  auto *buffer = LLVMSourceMgr.getMemoryBuffer(bufferID);
  SourceLoc start{llvm::SMLoc::getFromPointer(buffer->getBufferStart())};
  return CharSourceRange(start, buffer->getBufferSize());
}

unsigned SourceManager::getLocOffsetInBuffer(SourceLoc Loc,
                                             unsigned BufferID) const {
  assert(Loc.isValid() && "location should be valid");
  auto *Buffer = LLVMSourceMgr.getMemoryBuffer(BufferID);
  assert(Loc.Value.getPointer() >= Buffer->getBuffer().begin() &&
         Loc.Value.getPointer() <= Buffer->getBuffer().end() &&
         "Location is not from the specified buffer");
  return Loc.Value.getPointer() - Buffer->getBuffer().begin();
}

unsigned SourceManager::getByteDistance(SourceLoc Start, SourceLoc End) const {
  assert(Start.isValid() && "start location should be valid");
  assert(End.isValid() && "end location should be valid");
#ifndef NDEBUG
  unsigned BufferID = findBufferContainingLoc(Start);
  auto *Buffer = LLVMSourceMgr.getMemoryBuffer(BufferID);
  assert(End.Value.getPointer() >= Buffer->getBuffer().begin() &&
         End.Value.getPointer() <= Buffer->getBuffer().end() &&
         "End location is not from the same buffer");
#endif
  // When we have a rope buffer, could be implemented in terms of
  // getLocOffsetInBuffer().
  return End.Value.getPointer() - Start.Value.getPointer();
}

StringRef SourceManager::getEntireTextForBuffer(unsigned BufferID) const {
  return LLVMSourceMgr.getMemoryBuffer(BufferID)->getBuffer();
}

StringRef SourceManager::extractText(CharSourceRange Range,
                                     Optional<unsigned> BufferID) const {
  assert(Range.isValid() && "range should be valid");

  if (!BufferID)
    BufferID = findBufferContainingLoc(Range.getStart());
  StringRef Buffer = LLVMSourceMgr.getMemoryBuffer(*BufferID)->getBuffer();
  return Buffer.substr(getLocOffsetInBuffer(Range.getStart(), *BufferID),
                       Range.getByteLength());
}

Optional<unsigned>
SourceManager::findBufferContainingLocInternal(SourceLoc Loc) const {
  assert(Loc.isValid());
  // Search the buffers back-to front, so later alias buffers are
  // visited first.
  auto less_equal = std::less_equal<const char *>();
  for (unsigned i = LLVMSourceMgr.getNumBuffers(), e = 1; i >= e; --i) {
    auto Buf = LLVMSourceMgr.getMemoryBuffer(i);
    if (less_equal(Buf->getBufferStart(), Loc.Value.getPointer()) &&
        // Use <= here so that a pointer to the null at the end of the buffer
        // is included as part of the buffer.
        less_equal(Loc.Value.getPointer(), Buf->getBufferEnd()))
      return i;
  }
  return None;
}

unsigned SourceManager::findBufferContainingLoc(SourceLoc Loc) const {
  auto Id = findBufferContainingLocInternal(Loc);
  if (Id.hasValue())
    return *Id;
  llvm_unreachable("no buffer containing location found");
}

bool SourceManager::isOwning(SourceLoc Loc) const {
  return findBufferContainingLocInternal(Loc).hasValue();
}

void SourceRange::widen(SourceRange Other) {
  if (Other.Start.Value.getPointer() < Start.Value.getPointer())
    Start = Other.Start;
  if (Other.End.Value.getPointer() > End.Value.getPointer())
    End = Other.End;
}

void SourceLoc::printLineAndColumn(raw_ostream &OS, const SourceManager &SM,
                                   unsigned BufferID) const {
  if (isInvalid()) {
    OS << "<invalid loc>";
    return;
  }

  auto LineAndCol = SM.getPresumedLineAndColumnForLoc(*this, BufferID);
  OS << "line:" << LineAndCol.first << ':' << LineAndCol.second;
}

void SourceLoc::print(raw_ostream &OS, const SourceManager &SM,
                      unsigned &LastBufferID) const {
  if (isInvalid()) {
    OS << "<invalid loc>";
    return;
  }

  unsigned BufferID = SM.findBufferContainingLoc(*this);
  if (BufferID != LastBufferID) {
    OS << SM.getIdentifierForBuffer(BufferID);
    LastBufferID = BufferID;
  } else {
    OS << "line";
  }

  auto LineAndCol = SM.getPresumedLineAndColumnForLoc(*this, BufferID);
  OS << ':' << LineAndCol.first << ':' << LineAndCol.second;
}

void SourceLoc::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

void SourceRange::print(raw_ostream &OS, const SourceManager &SM,
                        unsigned &LastBufferID, bool PrintText) const {
  // FIXME: CharSourceRange is a half-open character-based range, while
  // SourceRange is a closed token-based range, so this conversion omits the
  // last token in the range. Unfortunately, we can't actually get to the end
  // of the token without using the Lex library, which would be a layering
  // violation. This is still better than nothing.
  CharSourceRange(SM, Start, End).print(OS, SM, LastBufferID, PrintText);
}

void SourceRange::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

CharSourceRange::CharSourceRange(const SourceManager &SM, SourceLoc Start,
                                 SourceLoc End)
    : Start(Start) {
  assert(Start.isValid() == End.isValid() &&
         "Start and end should either both be valid or both be invalid!");
  if (Start.isValid())
    ByteLength = SM.getByteDistance(Start, End);
}

void CharSourceRange::print(raw_ostream &OS, const SourceManager &SM,
                            unsigned &LastBufferID, bool PrintText) const {
  OS << '[';
  Start.print(OS, SM, LastBufferID);
  OS << " - ";
  getEnd().print(OS, SM, LastBufferID);
  OS << ']';

  if (Start.isInvalid() || getEnd().isInvalid())
    return;

  if (PrintText) {
    OS << " RangeText=\"" << SM.extractText(*this) << '"';
  }
}

void CharSourceRange::dump(const SourceManager &SM) const {
  print(llvm::errs(), SM);
}

llvm::Optional<unsigned>
SourceManager::resolveOffsetForEndOfLine(unsigned BufferId,
                                         unsigned Line) const {
  return resolveFromLineCol(BufferId, Line, ~0u);
}

llvm::Optional<unsigned>
SourceManager::getLineLength(unsigned BufferId, unsigned Line) const {
  auto BegOffset = resolveFromLineCol(BufferId, Line, 0);
  auto EndOffset = resolveFromLineCol(BufferId, Line, ~0u);
  if (BegOffset && EndOffset) {
     return EndOffset.getValue() - BegOffset.getValue();
  }
  return None;
}

llvm::Optional<unsigned> SourceManager::resolveFromLineCol(unsigned BufferId,
                                                           unsigned Line,
                                                           unsigned Col) const {
  if (Line == 0) {
    return None;
  }
  const bool LineEnd = (Col == ~0u);
  if (LineEnd)
    Col = 0;

  auto loc = const_cast<SourceManager *>(this)
                 ->getLLVMSourceMgr()
                 .FindLocForLineAndColumn(BufferId, Line, Col);
  if (!loc.isValid())
    return None;

  auto InputBuf = getLLVMSourceMgr().getMemoryBuffer(BufferId);
  const char *Ptr = loc.getPointer();
  if (LineEnd) {
    const char *End = InputBuf->getBufferEnd();
    for (;; ++Ptr) {
      if (Ptr == End || *Ptr == '\n')
        break;
    }
  }
  return Ptr - InputBuf->getBufferStart();
}

unsigned SourceManager::getExternalSourceBufferId(StringRef Path) {
  auto It = BufIdentIDMap.find(Path);
  if (It != BufIdentIDMap.end()) {
    return It->getSecond();
  }
  unsigned Id = 0u;
  auto InputFileOrErr = swift::vfs::getFileOrSTDIN(*getFileSystem(), Path);
  if (InputFileOrErr) {
    // This assertion ensures we can look up from the map in the future when
    // using the same Path.
    assert(InputFileOrErr.get()->getBufferIdentifier() == Path);
    Id = addNewSourceBuffer(std::move(InputFileOrErr.get()));
  }
  return Id;
}

SourceLoc
SourceManager::getLocFromExternalSource(StringRef Path, unsigned Line,
                                        unsigned Col) {
  auto BufferId = getExternalSourceBufferId(Path);
  if (BufferId == 0u)
    return SourceLoc();
  auto Offset = resolveFromLineCol(BufferId, Line, Col);
  if (!Offset.hasValue())
    return SourceLoc();
  return getLocForOffset(BufferId, *Offset);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2017 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <iostream>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>

namespace v2m = vcf2multialign;

typedef boost::bimap <
	boost::bimaps::multiset_of <size_t>,
	boost::bimaps::multiset_of <size_t>
> overlap_map;

typedef boost::bimap <
	boost::bimaps::set_of <size_t>,
	boost::bimaps::list_of <size_t>
> conflict_count_map;

namespace {

	template <typename t_map>
	void check_overlap(
		t_map &bad_overlap_side,
		conflict_count_map &conflict_counts,
		v2m::variant_set &skipped_variants,
		size_t const var_lineno,
		v2m::error_logger &error_logger
	)
	{
		auto const range(bad_overlap_side.equal_range(var_lineno));
		if (! (bad_overlap_side.end() == range.first || range.first == range.second))
		{
			if (error_logger.is_logging_errors())
			{
				for (auto it(range.first); it != range.second; ++it)
					error_logger.log_conflicting_variants(var_lineno, it->second);
			}

			// Update conflict counts.
			for (auto it(range.first); it != range.second; ++it)
			{
				auto c_it(conflict_counts.left.find(it->second));
				if (conflict_counts.left.end() == c_it)
					throw std::runtime_error("Unable to find conflict count for variant");

				auto &val(c_it->second);
				--val;

				if (0 == val)
					conflict_counts.left.erase(c_it);

				// In case 0 == val, bad_overlaps need not be updated b.c. the entries have
				// already been erased as part of handling previous overlapping variants.
			}

			skipped_variants.insert(var_lineno); // May be done without checking b.c. skipped_variants is a set.
			bad_overlap_side.erase(range.first, range.second);
		}
	}
}

namespace vcf2multialign {

	size_t check_overlapping_non_nested_variants(
		vcf_reader &reader,
		variant_set /* out */ &skipped_variants,
		variant_set /* out */ &non_nested_variants,
		error_logger &error_logger
	)
	{
		typedef boost::bimap <
			boost::bimaps::multiset_of <size_t>,
			boost::bimaps::multiset_of <size_t>
		> overlap_map;

		size_t last_position(0);
		std::map <size_t, size_t> end_positions;
		std::map <size_t, size_t, std::greater <size_t>> current_end_positions; // End positions for variants that have the same POS.
		conflict_count_map conflict_counts;
		overlap_map bad_overlaps;
		size_t i(0);
		size_t conflict_count(0);

		reader.reset();
		reader.set_parsed_fields(vcf_field::REF);
		variant var(reader.sample_count());
		while (reader.get_next_variant(var))
		{
			// Verify that the positions are in increasing order.
			auto const pos(var.zero_based_pos());

			if (! (last_position <= pos))
				throw std::runtime_error("Positions not in increasing order");

			auto const end(pos + var.ref().size());
			auto const var_lineno(var.lineno());

			if (last_position != pos)
				current_end_positions.clear();

			// Check end position order.
			if (last_position == pos)
			{
				auto const it(current_end_positions.upper_bound(end));
				if (current_end_positions.cend() != it)
				{
					non_nested_variants.emplace(var_lineno);
					non_nested_variants.emplace(it->second);
				}
				current_end_positions.emplace(end, var_lineno);
			}

			// Try to find an end position that is greater than var's position.
			auto it(end_positions.upper_bound(pos));
			auto const end_it(end_positions.cend());

			if (end_it == it)
			{
				end_positions.emplace(end, var_lineno);
				goto loop_end;
			}

			// Check that the found position is not within var's range.
			// If it is, continue checking succeeding positions.
			do
			{
				// Proper nesting.
				if (end <= it->first)
					break;

				++conflict_count;
				std::cerr << "Variant on line " << var_lineno << " conflicts with line " << it->second << "." << std::endl;

				auto const res(bad_overlaps.insert(overlap_map::value_type(it->second, var_lineno)));
				if (false == res.second)
					throw std::runtime_error("Unable to insert");

				++conflict_counts.left[it->second];
				++conflict_counts.left[var_lineno];
				++it;
			} while (end_it != it);

			// Add the end position.
			end_positions.emplace(end, var_lineno);

		loop_end:
			last_position = pos;

			++i;
			if (0 == i % 100000)
				std::cerr << "Handled " << i << " variants…" << std::endl;
		}

		// Remove conflicting variants starting from the one with the highest score.
		while (!conflict_counts.empty())
		{
			conflict_counts.right.sort();

			auto const it(conflict_counts.right.rbegin());
			auto const count(it->first);
			auto const var_lineno(it->second);

			// Check if the candidate variant is still listed.
			check_overlap(bad_overlaps.left, conflict_counts, skipped_variants, var_lineno, error_logger);
			check_overlap(bad_overlaps.right, conflict_counts, skipped_variants, var_lineno, error_logger);
			conflict_counts.left.erase(var_lineno);
		}

		if (bad_overlaps.size() != 0)
			throw std::runtime_error("Unable to remove all conflicting variants");

		return conflict_count;
	}
}
<commit_msg>Multiple variants may have the same ending positions<commit_after>/*
 * Copyright (c) 2017 Tuukka Norri
 * This code is licensed under MIT license (see LICENSE for details).
 */

#include <boost/bimap.hpp>
#include <boost/bimap/list_of.hpp>
#include <boost/bimap/multiset_of.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <iostream>
#include <vcf2multialign/check_overlapping_non_nested_variants.hh>

namespace v2m = vcf2multialign;

typedef boost::bimap <
	boost::bimaps::multiset_of <size_t>,
	boost::bimaps::multiset_of <size_t>
> overlap_map;

typedef boost::bimap <
	boost::bimaps::set_of <size_t>,
	boost::bimaps::list_of <size_t>
> conflict_count_map;

namespace {

	template <typename t_map>
	void check_overlap(
		t_map &bad_overlap_side,
		conflict_count_map &conflict_counts,
		v2m::variant_set &skipped_variants,
		size_t const var_lineno,
		v2m::error_logger &error_logger
	)
	{
		auto const range(bad_overlap_side.equal_range(var_lineno));
		if (! (bad_overlap_side.end() == range.first || range.first == range.second))
		{
			if (error_logger.is_logging_errors())
			{
				for (auto it(range.first); it != range.second; ++it)
					error_logger.log_conflicting_variants(var_lineno, it->second);
			}

			// Update conflict counts.
			for (auto it(range.first); it != range.second; ++it)
			{
				auto c_it(conflict_counts.left.find(it->second));
				if (conflict_counts.left.end() == c_it)
					throw std::runtime_error("Unable to find conflict count for variant");

				auto &val(c_it->second);
				--val;

				if (0 == val)
					conflict_counts.left.erase(c_it);

				// In case 0 == val, bad_overlaps need not be updated b.c. the entries have
				// already been erased as part of handling previous overlapping variants.
			}

			skipped_variants.insert(var_lineno); // May be done without checking b.c. skipped_variants is a set.
			bad_overlap_side.erase(range.first, range.second);
		}
	}
}

namespace vcf2multialign {

	size_t check_overlapping_non_nested_variants(
		vcf_reader &reader,
		variant_set /* out */ &skipped_variants,
		variant_set /* out */ &non_nested_variants,
		error_logger &error_logger
	)
	{
		typedef boost::bimap <
			boost::bimaps::multiset_of <size_t>,
			boost::bimaps::multiset_of <size_t>
		> overlap_map;

		size_t last_position(0);
		std::multimap <size_t, size_t> end_positions;
		std::multimap <size_t, size_t, std::greater <size_t>> current_end_positions; // End positions for variants that have the same POS.
		conflict_count_map conflict_counts;
		overlap_map bad_overlaps;
		size_t i(0);
		size_t conflict_count(0);

		reader.reset();
		reader.set_parsed_fields(vcf_field::REF);
		variant var(reader.sample_count());
		while (reader.get_next_variant(var))
		{
			// Verify that the positions are in increasing order.
			auto const pos(var.zero_based_pos());

			if (! (last_position <= pos))
				throw std::runtime_error("Positions not in increasing order");

			auto const end(pos + var.ref().size());
			auto const var_lineno(var.lineno());

			if (last_position != pos)
				current_end_positions.clear();

			// Check end position order.
			if (last_position == pos)
			{
				auto const it(current_end_positions.upper_bound(end));
				if (current_end_positions.cend() != it)
				{
					non_nested_variants.emplace(var_lineno);
					non_nested_variants.emplace(it->second);
				}
				current_end_positions.emplace(end, var_lineno);
			}

			// Try to find an end position that is greater than var's position.
			auto it(end_positions.upper_bound(pos));
			auto const end_it(end_positions.cend());

			if (end_it == it)
			{
				end_positions.emplace(end, var_lineno);
				goto loop_end;
			}

			// Check that the found position is not within var's range.
			// If it is, continue checking succeeding positions.
			do
			{
				// Proper nesting.
				if (end <= it->first)
					break;

				++conflict_count;
				std::cerr << "Variant on line " << var_lineno << " conflicts with line " << it->second << "." << std::endl;

				auto const res(bad_overlaps.insert(overlap_map::value_type(it->second, var_lineno)));
				if (false == res.second)
					throw std::runtime_error("Unable to insert");

				++conflict_counts.left[it->second];
				++conflict_counts.left[var_lineno];
				++it;
			} while (end_it != it);

			// Add the end position.
			end_positions.emplace(end, var_lineno);

		loop_end:
			last_position = pos;

			++i;
			if (0 == i % 100000)
				std::cerr << "Handled " << i << " variants…" << std::endl;
		}

		// Remove conflicting variants starting from the one with the highest score.
		while (!conflict_counts.empty())
		{
			conflict_counts.right.sort();

			auto const it(conflict_counts.right.rbegin());
			auto const count(it->first);
			auto const var_lineno(it->second);

			// Check if the candidate variant is still listed.
			check_overlap(bad_overlaps.left, conflict_counts, skipped_variants, var_lineno, error_logger);
			check_overlap(bad_overlaps.right, conflict_counts, skipped_variants, var_lineno, error_logger);
			conflict_counts.left.erase(var_lineno);
		}

		if (bad_overlaps.size() != 0)
			throw std::runtime_error("Unable to remove all conflicting variants");

		return conflict_count;
	}
}
<|endoftext|>