<commit_before>//===---- LiveRangeCalc.cpp - Calculate live ranges -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implementation of the LiveRangeCalc class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "LiveRangeCalc.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;

void LiveRangeCalc::reset(const MachineFunction *MF,
                          SlotIndexes *SI,
                          MachineDominatorTree *MDT,
                          VNInfo::Allocator *VNIA) {
  MRI = &MF->getRegInfo();
  Indexes = SI;
  DomTree = MDT;
  Alloc = VNIA;

  unsigned N = MF->getNumBlockIDs();
  Seen.clear();
  Seen.resize(N);
  LiveOut.resize(N);
  LiveIn.clear();
}

void LiveRangeCalc::createDeadDefs(LiveInterval *LI, unsigned Reg) {
  assert(MRI && Indexes && "call reset() first");

  // Visit all def operands. If the same instruction has multiple defs of Reg,
  // LI->createDeadDef() will deduplicate.
  for (MachineRegisterInfo::def_iterator
       I = MRI->def_begin(Reg), E = MRI->def_end(); I != E; ++I) {
    const MachineInstr *MI = &*I;
    // Find the corresponding slot index.
    SlotIndex Idx;
    if (MI->isPHI())
      // PHI defs begin at the basic block start index.
      Idx = Indexes->getMBBStartIdx(MI->getParent());
    else
      // Instructions are either normal 'r', or early clobber 'e'.
      Idx = Indexes->getInstructionIndex(MI)
        .getRegSlot(I.getOperand().isEarlyClobber());

    // Create the def in LI. This may find an existing def.
    LI->createDeadDef(Idx, *Alloc);
  }
}

void LiveRangeCalc::extendToUses(LiveInterval *LI, unsigned Reg) {
  assert(MRI && Indexes && "call reset() first");

  // Visit all operands that read Reg. This may include partial defs.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI->reg_nodbg_begin(Reg),
       E = MRI->reg_nodbg_end(); I != E; ++I) {
    const MachineOperand &MO = I.getOperand();
    if (!MO.readsReg())
      continue;
    // MI is reading Reg. We may have visited MI before if it happens to be
    // reading Reg multiple times. That is OK, extend() is idempotent.
    const MachineInstr *MI = &*I;

    // Find the SlotIndex being read.
    SlotIndex Idx;
    if (MI->isPHI()) {
      assert(!MO.isDef() && "Cannot handle PHI def of partial register.");
      // PHI operands are paired: (Reg, PredMBB).
      // Extend the live range to be live-out from PredMBB.
      Idx = Indexes->getMBBEndIdx(MI->getOperand(I.getOperandNo()+1).getMBB());
    } else {
      // This is a normal instruction.
      Idx = Indexes->getInstructionIndex(MI).getRegSlot();
      // Check for early-clobber redefs.
      unsigned DefIdx;
      if (MO.isDef()) {
        if (MO.isEarlyClobber())
          Idx = Idx.getRegSlot(true);
      } else if (MI->isRegTiedToDefOperand(I.getOperandNo(), &DefIdx)) {
        // FIXME: This would be a lot easier if tied early-clobber uses also
        // had an early-clobber flag.
        if (MI->getOperand(DefIdx).isEarlyClobber())
          Idx = Idx.getRegSlot(true);
      }
    }
    extend(LI, Idx, Reg);
  }
}

// Transfer information from the LiveIn vector to the live ranges.
void LiveRangeCalc::updateLiveIns(VNInfo *OverrideVNI) {
  for (SmallVectorImpl<LiveInBlock>::iterator I = LiveIn.begin(),
         E = LiveIn.end(); I != E; ++I) {
    if (!I->DomNode)
      continue;
    MachineBasicBlock *MBB = I->DomNode->getBlock();

    VNInfo *VNI = OverrideVNI ? OverrideVNI : I->Value;
    assert(VNI && "No live-in value found");

    SlotIndex Start, End;
    tie(Start, End) = Indexes->getMBBRange(MBB);

    if (I->Kill.isValid())
      I->LI->addRange(LiveRange(Start, I->Kill, VNI));
    else {
      I->LI->addRange(LiveRange(Start, End, VNI));
      // The value is live-through, update LiveOut as well.  Defer the Domtree
      // lookup until it is needed.
      assert(Seen.test(MBB->getNumber()));
      LiveOut[MBB] = LiveOutPair(VNI, (MachineDomTreeNode *)0);
    }
  }
  LiveIn.clear();
}

void LiveRangeCalc::extend(LiveInterval *LI,
                           SlotIndex Kill,
                           unsigned PhysReg) {
  assert(LI && "Missing live range");
  assert(Kill.isValid() && "Invalid SlotIndex");
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");

  MachineBasicBlock *KillMBB = Indexes->getMBBFromIndex(Kill.getPrevSlot());
  assert(KillMBB && "No MBB at Kill");

  // Is there a def in the same MBB we can extend?
  if (LI->extendInBlock(Indexes->getMBBStartIdx(KillMBB), Kill))
    return;

  // Find the single reaching def, or determine if Kill is jointly dominated by
  // multiple values, and we may need to create even more phi-defs to preserve
  // VNInfo SSA form.  Perform a search for all predecessor blocks where we
  // know the dominating VNInfo.
  VNInfo *VNI = findReachingDefs(LI, KillMBB, Kill, PhysReg);

  // When there were multiple different values, we may need new PHIs.
  if (!VNI)
    updateSSA();

  updateLiveIns(VNI);
}

// This function is called by a client after using the low-level API to add
// live-out and live-in blocks.  The unique value optimization is not
// available, SplitEditor::transferValues handles that case directly anyway.
void LiveRangeCalc::calculateValues() {
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");
  updateSSA();
  updateLiveIns(0);
}

VNInfo *LiveRangeCalc::findReachingDefs(LiveInterval *LI,
                                        MachineBasicBlock *KillMBB,
                                        SlotIndex Kill,
                                        unsigned PhysReg) {
  // Blocks where LI should be live-in.
  SmallVector<MachineBasicBlock*, 16> WorkList(1, KillMBB);

  // Remember if we have seen more than one value.
  bool UniqueVNI = true;
  VNInfo *TheVNI = 0;

  // Using Seen as a visited set, perform a BFS for all reaching defs.
  for (unsigned i = 0; i != WorkList.size(); ++i) {
    MachineBasicBlock *MBB = WorkList[i];

#ifndef NDEBUG
    if (MBB->pred_empty()) {
      MBB->getParent()->verify();
      llvm_unreachable("Use not jointly dominated by defs.");
    }

    if (TargetRegisterInfo::isPhysicalRegister(PhysReg) &&
        !MBB->isLiveIn(PhysReg)) {
      MBB->getParent()->verify();
      errs() << "The register needs to be live in to BB#" << MBB->getNumber()
             << ", but is missing from the live-in list.\n";
      llvm_unreachable("Invalid global physical register");
    }
#endif

    for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
           PE = MBB->pred_end(); PI != PE; ++PI) {
       MachineBasicBlock *Pred = *PI;

       // Is this a known live-out block?
       if (Seen.test(Pred->getNumber())) {
         if (VNInfo *VNI = LiveOut[Pred].first) {
           if (TheVNI && TheVNI != VNI)
             UniqueVNI = false;
           TheVNI = VNI;
         }
         continue;
       }

       SlotIndex Start, End;
       tie(Start, End) = Indexes->getMBBRange(Pred);

       // First time we see Pred.  Try to determine the live-out value, but set
       // it as null if Pred is live-through with an unknown value.
       VNInfo *VNI = LI->extendInBlock(Start, End);
       setLiveOutValue(Pred, VNI);
       if (VNI) {
         if (TheVNI && TheVNI != VNI)
           UniqueVNI = false;
         TheVNI = VNI;
         continue;
       }

       // No, we need a live-in value for Pred as well
       if (Pred != KillMBB)
          WorkList.push_back(Pred);
       else
          // Loopback to KillMBB, so value is really live through.
         Kill = SlotIndex();
    }
  }

  // Transfer WorkList to LiveInBlocks in reverse order.
  // This ordering works best with updateSSA().
  LiveIn.clear();
  LiveIn.reserve(WorkList.size());
  while(!WorkList.empty())
    addLiveInBlock(LI, DomTree->getNode(WorkList.pop_back_val()));

  // The kill block may not be live-through.
  assert(LiveIn.back().DomNode->getBlock() == KillMBB);
  LiveIn.back().Kill = Kill;

  return UniqueVNI ? TheVNI : 0;
}

// This is essentially the same iterative algorithm that SSAUpdater uses,
// except we already have a dominator tree, so we don't have to recompute it.
void LiveRangeCalc::updateSSA() {
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");

  // Interate until convergence.
  unsigned Changes;
  do {
    Changes = 0;
    // Propagate live-out values down the dominator tree, inserting phi-defs
    // when necessary.
    for (SmallVectorImpl<LiveInBlock>::iterator I = LiveIn.begin(),
           E = LiveIn.end(); I != E; ++I) {
      MachineDomTreeNode *Node = I->DomNode;
      // Skip block if the live-in value has already been determined.
      if (!Node)
        continue;
      MachineBasicBlock *MBB = Node->getBlock();
      MachineDomTreeNode *IDom = Node->getIDom();
      LiveOutPair IDomValue;

      // We need a live-in value to a block with no immediate dominator?
      // This is probably an unreachable block that has survived somehow.
      bool needPHI = !IDom || !Seen.test(IDom->getBlock()->getNumber());

      // IDom dominates all of our predecessors, but it may not be their
      // immediate dominator. Check if any of them have live-out values that are
      // properly dominated by IDom. If so, we need a phi-def here.
      if (!needPHI) {
        IDomValue = LiveOut[IDom->getBlock()];

        // Cache the DomTree node that defined the value.
        if (IDomValue.first && !IDomValue.second)
          LiveOut[IDom->getBlock()].second = IDomValue.second =
            DomTree->getNode(Indexes->getMBBFromIndex(IDomValue.first->def));

        for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
               PE = MBB->pred_end(); PI != PE; ++PI) {
          LiveOutPair &Value = LiveOut[*PI];
          if (!Value.first || Value.first == IDomValue.first)
            continue;

          // Cache the DomTree node that defined the value.
          if (!Value.second)
            Value.second =
              DomTree->getNode(Indexes->getMBBFromIndex(Value.first->def));

          // This predecessor is carrying something other than IDomValue.
          // It could be because IDomValue hasn't propagated yet, or it could be
          // because MBB is in the dominance frontier of that value.
          if (DomTree->dominates(IDom, Value.second)) {
            needPHI = true;
            break;
          }
        }
      }

      // The value may be live-through even if Kill is set, as can happen when
      // we are called from extendRange. In that case LiveOutSeen is true, and
      // LiveOut indicates a foreign or missing value.
      LiveOutPair &LOP = LiveOut[MBB];

      // Create a phi-def if required.
      if (needPHI) {
        ++Changes;
        assert(Alloc && "Need VNInfo allocator to create PHI-defs");
        SlotIndex Start, End;
        tie(Start, End) = Indexes->getMBBRange(MBB);
        VNInfo *VNI = I->LI->getNextValue(Start, *Alloc);
        I->Value = VNI;
        // This block is done, we know the final value.
        I->DomNode = 0;

        // Add liveness since updateLiveIns now skips this node.
        if (I->Kill.isValid())
          I->LI->addRange(LiveRange(Start, I->Kill, VNI));
        else {
          I->LI->addRange(LiveRange(Start, End, VNI));
          LOP = LiveOutPair(VNI, Node);
        }
      } else if (IDomValue.first) {
        // No phi-def here. Remember incoming value.
        I->Value = IDomValue.first;

        // If the IDomValue is killed in the block, don't propagate through.
        if (I->Kill.isValid())
          continue;

        // Propagate IDomValue if it isn't killed:
        // MBB is live-out and doesn't define its own value.
        if (LOP.first == IDomValue.first)
          continue;
        ++Changes;
        LOP = IDomValue;
      }
    }
  } while (Changes);
}
<commit_msg>Clear kill flags while computing live ranges.<commit_after>//===---- LiveRangeCalc.cpp - Calculate live ranges -----------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Implementation of the LiveRangeCalc class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "regalloc"
#include "LiveRangeCalc.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"

using namespace llvm;

void LiveRangeCalc::reset(const MachineFunction *MF,
                          SlotIndexes *SI,
                          MachineDominatorTree *MDT,
                          VNInfo::Allocator *VNIA) {
  MRI = &MF->getRegInfo();
  Indexes = SI;
  DomTree = MDT;
  Alloc = VNIA;

  unsigned N = MF->getNumBlockIDs();
  Seen.clear();
  Seen.resize(N);
  LiveOut.resize(N);
  LiveIn.clear();
}

void LiveRangeCalc::createDeadDefs(LiveInterval *LI, unsigned Reg) {
  assert(MRI && Indexes && "call reset() first");

  // Visit all def operands. If the same instruction has multiple defs of Reg,
  // LI->createDeadDef() will deduplicate.
  for (MachineRegisterInfo::def_iterator
       I = MRI->def_begin(Reg), E = MRI->def_end(); I != E; ++I) {
    const MachineInstr *MI = &*I;
    // Find the corresponding slot index.
    SlotIndex Idx;
    if (MI->isPHI())
      // PHI defs begin at the basic block start index.
      Idx = Indexes->getMBBStartIdx(MI->getParent());
    else
      // Instructions are either normal 'r', or early clobber 'e'.
      Idx = Indexes->getInstructionIndex(MI)
        .getRegSlot(I.getOperand().isEarlyClobber());

    // Create the def in LI. This may find an existing def.
    LI->createDeadDef(Idx, *Alloc);
  }
}

void LiveRangeCalc::extendToUses(LiveInterval *LI, unsigned Reg) {
  assert(MRI && Indexes && "call reset() first");

  // Visit all operands that read Reg. This may include partial defs.
  for (MachineRegisterInfo::reg_nodbg_iterator I = MRI->reg_nodbg_begin(Reg),
       E = MRI->reg_nodbg_end(); I != E; ++I) {
    MachineOperand &MO = I.getOperand();
    // Clear all kill flags. They will be reinserted after register allocation
    // by LiveIntervalAnalysis::addKillFlags().
    if (MO.isUse())
      MO.setIsKill(false);
    if (!MO.readsReg())
      continue;
    // MI is reading Reg. We may have visited MI before if it happens to be
    // reading Reg multiple times. That is OK, extend() is idempotent.
    const MachineInstr *MI = &*I;

    // Find the SlotIndex being read.
    SlotIndex Idx;
    if (MI->isPHI()) {
      assert(!MO.isDef() && "Cannot handle PHI def of partial register.");
      // PHI operands are paired: (Reg, PredMBB).
      // Extend the live range to be live-out from PredMBB.
      Idx = Indexes->getMBBEndIdx(MI->getOperand(I.getOperandNo()+1).getMBB());
    } else {
      // This is a normal instruction.
      Idx = Indexes->getInstructionIndex(MI).getRegSlot();
      // Check for early-clobber redefs.
      unsigned DefIdx;
      if (MO.isDef()) {
        if (MO.isEarlyClobber())
          Idx = Idx.getRegSlot(true);
      } else if (MI->isRegTiedToDefOperand(I.getOperandNo(), &DefIdx)) {
        // FIXME: This would be a lot easier if tied early-clobber uses also
        // had an early-clobber flag.
        if (MI->getOperand(DefIdx).isEarlyClobber())
          Idx = Idx.getRegSlot(true);
      }
    }
    extend(LI, Idx, Reg);
  }
}

// Transfer information from the LiveIn vector to the live ranges.
void LiveRangeCalc::updateLiveIns(VNInfo *OverrideVNI) {
  for (SmallVectorImpl<LiveInBlock>::iterator I = LiveIn.begin(),
         E = LiveIn.end(); I != E; ++I) {
    if (!I->DomNode)
      continue;
    MachineBasicBlock *MBB = I->DomNode->getBlock();

    VNInfo *VNI = OverrideVNI ? OverrideVNI : I->Value;
    assert(VNI && "No live-in value found");

    SlotIndex Start, End;
    tie(Start, End) = Indexes->getMBBRange(MBB);

    if (I->Kill.isValid())
      I->LI->addRange(LiveRange(Start, I->Kill, VNI));
    else {
      I->LI->addRange(LiveRange(Start, End, VNI));
      // The value is live-through, update LiveOut as well.  Defer the Domtree
      // lookup until it is needed.
      assert(Seen.test(MBB->getNumber()));
      LiveOut[MBB] = LiveOutPair(VNI, (MachineDomTreeNode *)0);
    }
  }
  LiveIn.clear();
}

void LiveRangeCalc::extend(LiveInterval *LI,
                           SlotIndex Kill,
                           unsigned PhysReg) {
  assert(LI && "Missing live range");
  assert(Kill.isValid() && "Invalid SlotIndex");
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");

  MachineBasicBlock *KillMBB = Indexes->getMBBFromIndex(Kill.getPrevSlot());
  assert(KillMBB && "No MBB at Kill");

  // Is there a def in the same MBB we can extend?
  if (LI->extendInBlock(Indexes->getMBBStartIdx(KillMBB), Kill))
    return;

  // Find the single reaching def, or determine if Kill is jointly dominated by
  // multiple values, and we may need to create even more phi-defs to preserve
  // VNInfo SSA form.  Perform a search for all predecessor blocks where we
  // know the dominating VNInfo.
  VNInfo *VNI = findReachingDefs(LI, KillMBB, Kill, PhysReg);

  // When there were multiple different values, we may need new PHIs.
  if (!VNI)
    updateSSA();

  updateLiveIns(VNI);
}

// This function is called by a client after using the low-level API to add
// live-out and live-in blocks.  The unique value optimization is not
// available, SplitEditor::transferValues handles that case directly anyway.
void LiveRangeCalc::calculateValues() {
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");
  updateSSA();
  updateLiveIns(0);
}

VNInfo *LiveRangeCalc::findReachingDefs(LiveInterval *LI,
                                        MachineBasicBlock *KillMBB,
                                        SlotIndex Kill,
                                        unsigned PhysReg) {
  // Blocks where LI should be live-in.
  SmallVector<MachineBasicBlock*, 16> WorkList(1, KillMBB);

  // Remember if we have seen more than one value.
  bool UniqueVNI = true;
  VNInfo *TheVNI = 0;

  // Using Seen as a visited set, perform a BFS for all reaching defs.
  for (unsigned i = 0; i != WorkList.size(); ++i) {
    MachineBasicBlock *MBB = WorkList[i];

#ifndef NDEBUG
    if (MBB->pred_empty()) {
      MBB->getParent()->verify();
      llvm_unreachable("Use not jointly dominated by defs.");
    }

    if (TargetRegisterInfo::isPhysicalRegister(PhysReg) &&
        !MBB->isLiveIn(PhysReg)) {
      MBB->getParent()->verify();
      errs() << "The register needs to be live in to BB#" << MBB->getNumber()
             << ", but is missing from the live-in list.\n";
      llvm_unreachable("Invalid global physical register");
    }
#endif

    for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
           PE = MBB->pred_end(); PI != PE; ++PI) {
       MachineBasicBlock *Pred = *PI;

       // Is this a known live-out block?
       if (Seen.test(Pred->getNumber())) {
         if (VNInfo *VNI = LiveOut[Pred].first) {
           if (TheVNI && TheVNI != VNI)
             UniqueVNI = false;
           TheVNI = VNI;
         }
         continue;
       }

       SlotIndex Start, End;
       tie(Start, End) = Indexes->getMBBRange(Pred);

       // First time we see Pred.  Try to determine the live-out value, but set
       // it as null if Pred is live-through with an unknown value.
       VNInfo *VNI = LI->extendInBlock(Start, End);
       setLiveOutValue(Pred, VNI);
       if (VNI) {
         if (TheVNI && TheVNI != VNI)
           UniqueVNI = false;
         TheVNI = VNI;
         continue;
       }

       // No, we need a live-in value for Pred as well
       if (Pred != KillMBB)
          WorkList.push_back(Pred);
       else
          // Loopback to KillMBB, so value is really live through.
         Kill = SlotIndex();
    }
  }

  // Transfer WorkList to LiveInBlocks in reverse order.
  // This ordering works best with updateSSA().
  LiveIn.clear();
  LiveIn.reserve(WorkList.size());
  while(!WorkList.empty())
    addLiveInBlock(LI, DomTree->getNode(WorkList.pop_back_val()));

  // The kill block may not be live-through.
  assert(LiveIn.back().DomNode->getBlock() == KillMBB);
  LiveIn.back().Kill = Kill;

  return UniqueVNI ? TheVNI : 0;
}

// This is essentially the same iterative algorithm that SSAUpdater uses,
// except we already have a dominator tree, so we don't have to recompute it.
void LiveRangeCalc::updateSSA() {
  assert(Indexes && "Missing SlotIndexes");
  assert(DomTree && "Missing dominator tree");

  // Interate until convergence.
  unsigned Changes;
  do {
    Changes = 0;
    // Propagate live-out values down the dominator tree, inserting phi-defs
    // when necessary.
    for (SmallVectorImpl<LiveInBlock>::iterator I = LiveIn.begin(),
           E = LiveIn.end(); I != E; ++I) {
      MachineDomTreeNode *Node = I->DomNode;
      // Skip block if the live-in value has already been determined.
      if (!Node)
        continue;
      MachineBasicBlock *MBB = Node->getBlock();
      MachineDomTreeNode *IDom = Node->getIDom();
      LiveOutPair IDomValue;

      // We need a live-in value to a block with no immediate dominator?
      // This is probably an unreachable block that has survived somehow.
      bool needPHI = !IDom || !Seen.test(IDom->getBlock()->getNumber());

      // IDom dominates all of our predecessors, but it may not be their
      // immediate dominator. Check if any of them have live-out values that are
      // properly dominated by IDom. If so, we need a phi-def here.
      if (!needPHI) {
        IDomValue = LiveOut[IDom->getBlock()];

        // Cache the DomTree node that defined the value.
        if (IDomValue.first && !IDomValue.second)
          LiveOut[IDom->getBlock()].second = IDomValue.second =
            DomTree->getNode(Indexes->getMBBFromIndex(IDomValue.first->def));

        for (MachineBasicBlock::pred_iterator PI = MBB->pred_begin(),
               PE = MBB->pred_end(); PI != PE; ++PI) {
          LiveOutPair &Value = LiveOut[*PI];
          if (!Value.first || Value.first == IDomValue.first)
            continue;

          // Cache the DomTree node that defined the value.
          if (!Value.second)
            Value.second =
              DomTree->getNode(Indexes->getMBBFromIndex(Value.first->def));

          // This predecessor is carrying something other than IDomValue.
          // It could be because IDomValue hasn't propagated yet, or it could be
          // because MBB is in the dominance frontier of that value.
          if (DomTree->dominates(IDom, Value.second)) {
            needPHI = true;
            break;
          }
        }
      }

      // The value may be live-through even if Kill is set, as can happen when
      // we are called from extendRange. In that case LiveOutSeen is true, and
      // LiveOut indicates a foreign or missing value.
      LiveOutPair &LOP = LiveOut[MBB];

      // Create a phi-def if required.
      if (needPHI) {
        ++Changes;
        assert(Alloc && "Need VNInfo allocator to create PHI-defs");
        SlotIndex Start, End;
        tie(Start, End) = Indexes->getMBBRange(MBB);
        VNInfo *VNI = I->LI->getNextValue(Start, *Alloc);
        I->Value = VNI;
        // This block is done, we know the final value.
        I->DomNode = 0;

        // Add liveness since updateLiveIns now skips this node.
        if (I->Kill.isValid())
          I->LI->addRange(LiveRange(Start, I->Kill, VNI));
        else {
          I->LI->addRange(LiveRange(Start, End, VNI));
          LOP = LiveOutPair(VNI, Node);
        }
      } else if (IDomValue.first) {
        // No phi-def here. Remember incoming value.
        I->Value = IDomValue.first;

        // If the IDomValue is killed in the block, don't propagate through.
        if (I->Kill.isValid())
          continue;

        // Propagate IDomValue if it isn't killed:
        // MBB is live-out and doesn't define its own value.
        if (LOP.first == IDomValue.first)
          continue;
        ++Changes;
        LOP = IDomValue;
      }
    }
  } while (Changes);
}
<|endoftext|>


<commit_before>//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

using namespace clang::diag;
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

namespace {
// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
                    std::string &Ver) {
  Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0");
  std::error_code EC;
  for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
       LI = LI.increment(EC)) {
    StringRef VersionText = llvm::sys::path::filename(LI->path());
    Generic_GCC::GCCVersion CandidateVersion =
        Generic_GCC::GCCVersion::Parse(VersionText);
    if (CandidateVersion.Major == -1)
      continue;
    if (CandidateVersion <= Version)
      continue;
    Ver = VersionText;
    GccLibDir = LI->path();
  }
  return Ver.size();
}
}

void MinGW::findGccLibDir() {
  llvm::SmallVector<llvm::SmallString<32>, 2> Archs;
  Archs.emplace_back(getTriple().getArchName());
  Archs[0] += "-w64-mingw32";
  Archs.emplace_back("mingw32");
  Arch = Archs[0].str();
  // lib: Arch Linux, Ubuntu, Windows
  // lib64: openSUSE Linux
  for (StringRef CandidateLib : {"lib", "lib64"}) {
    for (StringRef CandidateArch : Archs) {
      llvm::SmallString<1024> LibDir(Base);
      llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch);
      if (findGccVersion(LibDir, GccLibDir, Ver)) {
        Arch = CandidateArch;
        return;
      }
    }
  }
}

MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
  getProgramPaths().push_back(getDriver().getInstalledDir());

// In Windows there aren't any standard install locations, we search
// for gcc on the PATH. In Linux the base is always /usr.
#ifdef LLVM_ON_WIN32
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else if (llvm::ErrorOr<std::string> GPPName =
               llvm::sys::findProgramByName("gcc"))
    Base = llvm::sys::path::parent_path(
        llvm::sys::path::parent_path(GPPName.get()));
  else
    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
#else
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else
    Base = "/usr";
#endif

  Base += llvm::sys::path::get_separator();
  findGccLibDir();
  // GccLibDir must precede Base/lib so that the
  // correct crtbegin.o ,cetend.o would be found.
  getFilePaths().push_back(GccLibDir);
  getFilePaths().push_back(
      (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
  getFilePaths().push_back(Base + "lib");
  // openSUSE
  getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
}

bool MinGW::IsIntegratedAssemblerDefault() const { return true; }

Tool *MinGW::getTool(Action::ActionClass AC) const {
  switch (AC) {
  case Action::PreprocessJobClass:
    if (!Preprocessor)
      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
    return Preprocessor.get();
  case Action::CompileJobClass:
    if (!Compiler)
      Compiler.reset(new tools::gcc::Compiler(*this));
    return Compiler.get();
  default:
    return ToolChain::getTool(AC);
  }
}

Tool *MinGW::buildAssembler() const {
  return new tools::MinGW::Assembler(*this);
}

Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }

bool MinGW::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }

bool MinGW::isPIEDefault() const { return false; }

bool MinGW::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::UseSEHExceptions() const {
  return getArch() == llvm::Triple::x86_64;
}

void MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
                               ArgStringList &CC1Args) const {
  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
}

void MinGW::printVerboseInfo(raw_ostream &OS) const {
  CudaInstallation.print(OS);
}

// Include directories for various hosts:

// Windows, mingw.org
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
// c:\mingw\lib\gcc\mingw32\4.8.1\include
// c:\mingw\include
// c:\mingw\lib\gcc\mingw32\4.8.1\include-fixed
// c:\mingw\mingw32\include

// Windows, mingw-w64 mingw-builds
// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include
// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include-fixed
// c:\mingw32\i686-w64-mingw32\include
// c:\mingw32\i686-w64-mingw32\include\c++
// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
// c:\mingw32\i686-w64-mingw32\include\c++\backward

// Windows, mingw-w64 msys2
// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include
// c:\msys64\mingw32\include
// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include-fixed
// c:\msys64\mingw32\i686-w64-mingw32\include
// c:\msys64\mingw32\include\c++\4.9.2
// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
// c:\msys64\mingw32\include\c++\4.9.2\backward

// openSUSE
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include-fixed
// /usr/x86_64-w64-mingw32/sys-root/mingw/include

// Arch Linux
// /usr/i686-w64-mingw32/include/c++/5.1.0
// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
// /usr/i686-w64-mingw32/include/c++/5.1.0/backward
// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include
// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include-fixed
// /usr/i686-w64-mingw32/include

// Ubuntu
// /usr/include/c++/4.8
// /usr/include/c++/4.8/x86_64-w64-mingw32
// /usr/include/c++/4.8/backward
// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include
// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include-fixed
// /usr/x86_64-w64-mingw32/include

void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                      ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<1024> P(getDriver().ResourceDir);
    llvm::sys::path::append(P, "include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
    llvm::SmallString<1024> IncludeDir(GccLibDir);
    llvm::sys::path::append(IncludeDir, "include");
    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
    IncludeDir += "-fixed";
    // openSUSE
    addSystemInclude(DriverArgs, CC1Args,
                     Base + Arch + "/sys-root/mingw/include");
    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  }
  addSystemInclude(DriverArgs, CC1Args,
                   Base + Arch + llvm::sys::path::get_separator() + "include");
  addSystemInclude(DriverArgs, CC1Args, Base + "include");
}

void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                         ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
      DriverArgs.hasArg(options::OPT_nostdincxx))
    return;

  switch (GetCXXStdlibType(DriverArgs)) {
  case ToolChain::CST_Libcxx:
    addSystemInclude(DriverArgs, CC1Args,
                     Base + "include" + llvm::sys::path::get_separator() +
                         "c++" + llvm::sys::path::get_separator() + "v1");
    break;

  case ToolChain::CST_Libstdcxx:
    llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
    CppIncludeBases.emplace_back(GccLibDir);
    llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
    for (auto &CppIncludeBase : CppIncludeBases) {
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
      CppIncludeBase += llvm::sys::path::get_separator();
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
    }
    break;
  }
}
<commit_msg>[ToolChains] Use "static" instead of an anonymous namespace for a function.  NFC<commit_after>//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "ToolChains.h"
#include "clang/Driver/Driver.h"
#include "clang/Driver/Options.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"

using namespace clang::diag;
using namespace clang::driver;
using namespace clang::driver::toolchains;
using namespace clang;
using namespace llvm::opt;

// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple.
static bool findGccVersion(StringRef LibDir, std::string &GccLibDir,
                           std::string &Ver) {
  Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0");
  std::error_code EC;
  for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE;
       LI = LI.increment(EC)) {
    StringRef VersionText = llvm::sys::path::filename(LI->path());
    Generic_GCC::GCCVersion CandidateVersion =
        Generic_GCC::GCCVersion::Parse(VersionText);
    if (CandidateVersion.Major == -1)
      continue;
    if (CandidateVersion <= Version)
      continue;
    Ver = VersionText;
    GccLibDir = LI->path();
  }
  return Ver.size();
}

void MinGW::findGccLibDir() {
  llvm::SmallVector<llvm::SmallString<32>, 2> Archs;
  Archs.emplace_back(getTriple().getArchName());
  Archs[0] += "-w64-mingw32";
  Archs.emplace_back("mingw32");
  Arch = Archs[0].str();
  // lib: Arch Linux, Ubuntu, Windows
  // lib64: openSUSE Linux
  for (StringRef CandidateLib : {"lib", "lib64"}) {
    for (StringRef CandidateArch : Archs) {
      llvm::SmallString<1024> LibDir(Base);
      llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch);
      if (findGccVersion(LibDir, GccLibDir, Ver)) {
        Arch = CandidateArch;
        return;
      }
    }
  }
}

MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args)
    : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) {
  getProgramPaths().push_back(getDriver().getInstalledDir());

// In Windows there aren't any standard install locations, we search
// for gcc on the PATH. In Linux the base is always /usr.
#ifdef LLVM_ON_WIN32
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else if (llvm::ErrorOr<std::string> GPPName =
               llvm::sys::findProgramByName("gcc"))
    Base = llvm::sys::path::parent_path(
        llvm::sys::path::parent_path(GPPName.get()));
  else
    Base = llvm::sys::path::parent_path(getDriver().getInstalledDir());
#else
  if (getDriver().SysRoot.size())
    Base = getDriver().SysRoot;
  else
    Base = "/usr";
#endif

  Base += llvm::sys::path::get_separator();
  findGccLibDir();
  // GccLibDir must precede Base/lib so that the
  // correct crtbegin.o ,cetend.o would be found.
  getFilePaths().push_back(GccLibDir);
  getFilePaths().push_back(
      (Base + Arch + llvm::sys::path::get_separator() + "lib").str());
  getFilePaths().push_back(Base + "lib");
  // openSUSE
  getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib");
}

bool MinGW::IsIntegratedAssemblerDefault() const { return true; }

Tool *MinGW::getTool(Action::ActionClass AC) const {
  switch (AC) {
  case Action::PreprocessJobClass:
    if (!Preprocessor)
      Preprocessor.reset(new tools::gcc::Preprocessor(*this));
    return Preprocessor.get();
  case Action::CompileJobClass:
    if (!Compiler)
      Compiler.reset(new tools::gcc::Compiler(*this));
    return Compiler.get();
  default:
    return ToolChain::getTool(AC);
  }
}

Tool *MinGW::buildAssembler() const {
  return new tools::MinGW::Assembler(*this);
}

Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); }

bool MinGW::IsUnwindTablesDefault() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; }

bool MinGW::isPIEDefault() const { return false; }

bool MinGW::isPICDefaultForced() const {
  return getArch() == llvm::Triple::x86_64;
}

bool MinGW::UseSEHExceptions() const {
  return getArch() == llvm::Triple::x86_64;
}

void MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs,
                               ArgStringList &CC1Args) const {
  CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args);
}

void MinGW::printVerboseInfo(raw_ostream &OS) const {
  CudaInstallation.print(OS);
}

// Include directories for various hosts:

// Windows, mingw.org
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32
// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward
// c:\mingw\lib\gcc\mingw32\4.8.1\include
// c:\mingw\include
// c:\mingw\lib\gcc\mingw32\4.8.1\include-fixed
// c:\mingw\mingw32\include

// Windows, mingw-w64 mingw-builds
// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include
// c:\mingw32\lib\gcc\i686-w64-mingw32\4.9.1\include-fixed
// c:\mingw32\i686-w64-mingw32\include
// c:\mingw32\i686-w64-mingw32\include\c++
// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32
// c:\mingw32\i686-w64-mingw32\include\c++\backward

// Windows, mingw-w64 msys2
// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include
// c:\msys64\mingw32\include
// c:\msys64\mingw32\lib\gcc\i686-w64-mingw32\4.9.2\include-fixed
// c:\msys64\mingw32\i686-w64-mingw32\include
// c:\msys64\mingw32\include\c++\4.9.2
// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32
// c:\msys64\mingw32\include\c++\4.9.2\backward

// openSUSE
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include
// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include-fixed
// /usr/x86_64-w64-mingw32/sys-root/mingw/include

// Arch Linux
// /usr/i686-w64-mingw32/include/c++/5.1.0
// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32
// /usr/i686-w64-mingw32/include/c++/5.1.0/backward
// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include
// /usr/lib/gcc/i686-w64-mingw32/5.1.0/include-fixed
// /usr/i686-w64-mingw32/include

// Ubuntu
// /usr/include/c++/4.8
// /usr/include/c++/4.8/x86_64-w64-mingw32
// /usr/include/c++/4.8/backward
// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include
// /usr/lib/gcc/x86_64-w64-mingw32/4.8/include-fixed
// /usr/x86_64-w64-mingw32/include

void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs,
                                      ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdinc))
    return;

  if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) {
    SmallString<1024> P(getDriver().ResourceDir);
    llvm::sys::path::append(P, "include");
    addSystemInclude(DriverArgs, CC1Args, P.str());
  }

  if (DriverArgs.hasArg(options::OPT_nostdlibinc))
    return;

  if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) {
    llvm::SmallString<1024> IncludeDir(GccLibDir);
    llvm::sys::path::append(IncludeDir, "include");
    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
    IncludeDir += "-fixed";
    // openSUSE
    addSystemInclude(DriverArgs, CC1Args,
                     Base + Arch + "/sys-root/mingw/include");
    addSystemInclude(DriverArgs, CC1Args, IncludeDir.c_str());
  }
  addSystemInclude(DriverArgs, CC1Args,
                   Base + Arch + llvm::sys::path::get_separator() + "include");
  addSystemInclude(DriverArgs, CC1Args, Base + "include");
}

void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs,
                                         ArgStringList &CC1Args) const {
  if (DriverArgs.hasArg(options::OPT_nostdlibinc) ||
      DriverArgs.hasArg(options::OPT_nostdincxx))
    return;

  switch (GetCXXStdlibType(DriverArgs)) {
  case ToolChain::CST_Libcxx:
    addSystemInclude(DriverArgs, CC1Args,
                     Base + "include" + llvm::sys::path::get_separator() +
                         "c++" + llvm::sys::path::get_separator() + "v1");
    break;

  case ToolChain::CST_Libstdcxx:
    llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases;
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++");
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver);
    CppIncludeBases.emplace_back(Base);
    llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver);
    CppIncludeBases.emplace_back(GccLibDir);
    llvm::sys::path::append(CppIncludeBases[3], "include", "c++");
    for (auto &CppIncludeBase : CppIncludeBases) {
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase);
      CppIncludeBase += llvm::sys::path::get_separator();
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch);
      addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward");
    }
    break;
  }
}
<|endoftext|>


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

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

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

   See NOTICE file for details.
 *****************************************************************************/
#include <algorithm>
#include "jpype.h"
#include "jp_method.h"
#include "jp_methoddispatch.h"

JPMethodDispatch::JPMethodDispatch(JPClass* clazz,
		const string& name,
		JPMethodList& overloads,
		jint modifiers)
: m_Name(name)
{
	m_Class = clazz;
	m_Overloads = overloads;
	m_Modifiers = modifiers;
	m_LastCache.m_Cache = -1;
}

JPMethodDispatch::~JPMethodDispatch()
{
}

const string& JPMethodDispatch::getName() const
{
	return m_Name;
}

bool JPMethodDispatch::findOverload(JPJavaFrame& frame, JPMethodMatch &bestMatch, JPPyObjectVector& arg,
		bool callInstance, bool raise)
{
	JP_TRACE_IN("JPMethodDispatch::findOverload");
	JP_TRACE("Checking overload", m_Name);
	JP_TRACE("Got overloads to check", m_Overloads.size());
	JPMethodList ambiguous;
	JPMethodMatch match = bestMatch;

	// Check cache to see if we already resolved this
	if (m_LastCache.m_Cache == match.m_Cache)
	{
		bestMatch.m_Overload = m_LastCache.m_Overload;
		bestMatch.m_Overload->matches(frame, bestMatch, callInstance, arg);
		if (bestMatch.m_Type > JPMatch::_explicit)
			return true;
	}

	for (JPMethodList::iterator it = m_Overloads.begin(); it != m_Overloads.end(); ++it)
	{
		JPMethod* current = *it;

		// This would be hidden as we have a match with a more specific overload
		// already and it can't be exact.
		if (bestMatch.m_Type == JPMatch::_implicit && bestMatch.m_Overload->checkMoreSpecificThan(current))
			continue;

		JP_TRACE("Trying to match", current->toString());
		current->matches(frame, match, callInstance, arg);

		JP_TRACE("  match ended", match.m_Type);
		if (match.m_Type == JPMatch::_exact)
		{
			bestMatch = match;
			m_LastCache = match;
			return true;
		}
		if (match.m_Type < JPMatch::_implicit)
			continue;

		// If this is the first match then make it the best.
		if (bestMatch.m_Overload == 0)
		{
			bestMatch = match;
			continue;
		}

		// If the best does not hide the other, than we have ambiguity.
		if (!(bestMatch.m_Overload->checkMoreSpecificThan(current)))
		{
			// See if we can match based on instance
			if (callInstance == !current->isStatic())
			{
				// if current matches instance and best does not switch
				if (callInstance == bestMatch.m_Overload->isStatic())
				{
					bestMatch = match;
					continue;
				}
			} else
			{
				// if best matches instance and current does not, no ambiguity
				if (callInstance == !bestMatch.m_Overload->isStatic())
				{
					continue;
				}
			}

			JP_TRACE("Adding to ambiguous list");
			ambiguous.push_back(*it);
		}
	}

	// If we have an ambiguous overload report an error.
	if (!ambiguous.empty())
	{
		if (!raise)
			return false;
		ambiguous.push_back(bestMatch.m_Overload);

		// We have two possible overloads so we declare an error
		std::stringstream ss;
		if (JPModifier::isConstructor(m_Modifiers))
			ss << "Ambiguous overloads found for constructor " << m_Class->getCanonicalName() << "(";
		else
			ss << "Ambiguous overloads found for " << m_Class->getCanonicalName() << "." << getName() << "(";
		size_t start = callInstance ? 1 : 0;
		for (size_t i = start; i < arg.size(); ++i)
		{
			if (i != start)
				ss << ",";
			ss << Py_TYPE(arg[i])->tp_name;
		}
		ss << ")" << " between:" << std::endl;
		for (vector<JPMethod*>::iterator it = ambiguous.begin(); it != ambiguous.end(); ++it)
		{
			ss << "\t" << (*it)->toString() << std::endl;
		}
		JP_RAISE(PyExc_TypeError, ss.str());
		JP_TRACE(ss.str());
	}

	// If we can't find a matching overload throw an error.
	if (!bestMatch.m_Overload)
	{
		if (!raise)
			return false;
		std::stringstream ss;
		if (JPModifier::isConstructor(m_Modifiers))
			ss << "No matching overloads found for constructor " << m_Class->getCanonicalName() << "(";
		else
			ss << "No matching overloads found for " << m_Class->getCanonicalName() << "." << getName() << "(";
		size_t start = callInstance ? 1 : 0;
		for (size_t i = start; i < arg.size(); ++i)
		{
			if (i != start)
				ss << ",";
			ss << Py_TYPE(arg[i])->tp_name;
		}
		ss << ")" << ", options are:" << std::endl;
		for (JPMethodList::iterator it = m_Overloads.begin();
				it != m_Overloads.end();
				++it)
		{
			JPMethod* current = *it;
			ss << "\t" << current->toString();
			ss << std::endl;
		}
		JP_RAISE(PyExc_TypeError, ss.str());
	}

	// Set up a cache to bypass repeated calls.
	if (bestMatch.m_Type == JPMatch::_implicit)
	{
		m_LastCache = bestMatch;
	}

	JP_TRACE("Best match", bestMatch.m_Overload->toString());
	return true;
	JP_TRACE_OUT;
}

JPPyObject JPMethodDispatch::invoke(JPJavaFrame& frame, JPPyObjectVector& args, bool instance)
{
	JP_TRACE_IN("JPMethodDispatch::invoke");
	JPMethodMatch match(frame, args, instance);
	findOverload(frame, match, args, instance, true);
	return match.m_Overload->invoke(frame, match, args, instance);
	JP_TRACE_OUT;
}

JPValue JPMethodDispatch::invokeConstructor(JPJavaFrame& frame, JPPyObjectVector& args)
{
	JP_TRACE_IN("JPMethodDispatch::invokeConstructor");
	JPMethodMatch match(frame, args, false);
	findOverload(frame, match, args, false, true);
	return match.m_Overload->invokeConstructor(frame, match, args);
	JP_TRACE_OUT;
}

bool JPMethodDispatch::matches(JPJavaFrame& frame, JPPyObjectVector& args, bool instance)
{
	JP_TRACE_IN("JPMethodDispatch::invoke");
	JPMethodMatch match(frame, args, instance);
	return findOverload(frame, match, args, instance, false);
	JP_TRACE_OUT;  // GCOVR_EXCL_LINE
}

string JPMethodDispatch::matchReport(JPPyObjectVector& args)
{
	stringstream res;
	res << "Match report for method " << m_Name << ", has " << m_Overloads.size() << " overloads." << endl;

	for (JPMethodList::iterator cur = m_Overloads.begin(); cur != m_Overloads.end(); cur++)
	{
		JPMethod* current = *cur;
		res << "  " << current->matchReport(args);
	}
	return res.str();
}

<commit_msg>Fix caching.  Disable cache for Varargs.<commit_after>/*****************************************************************************
   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

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

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

   See NOTICE file for details.
 *****************************************************************************/
#include <algorithm>
#include "jpype.h"
#include "jp_method.h"
#include "jp_methoddispatch.h"

JPMethodDispatch::JPMethodDispatch(JPClass* clazz,
		const string& name,
		JPMethodList& overloads,
		jint modifiers)
: m_Name(name)
{
	m_Class = clazz;
	m_Overloads = overloads;
	m_Modifiers = modifiers;
	m_LastCache.m_Cache = -1;
}

JPMethodDispatch::~JPMethodDispatch()
{
}

const string& JPMethodDispatch::getName() const
{
	return m_Name;
}

bool JPMethodDispatch::findOverload(JPJavaFrame& frame, JPMethodMatch &bestMatch, JPPyObjectVector& arg,
		bool callInstance, bool raise)
{
	JP_TRACE_IN("JPMethodDispatch::findOverload");
	JP_TRACE("Checking overload", m_Name);
	JP_TRACE("Got overloads to check", m_Overloads.size());
	JPMethodList ambiguous;
	JPMethodMatch match = bestMatch;

	// Check cache to see if we already resolved this
	if (m_LastCache.m_Cache == match.m_Cache && !m_LastCache.m_Overload->isVarArgs())
	{
		bestMatch.m_Overload = m_LastCache.m_Overload;
		bestMatch.m_Overload->matches(frame, bestMatch, callInstance, arg);
		if (bestMatch.m_Type > JPMatch::_explicit)
			return true;
	}

	for (JPMethodList::iterator it = m_Overloads.begin(); it != m_Overloads.end(); ++it)
	{
		JPMethod* current = *it;

		JP_TRACE("Trying to match", current->toString());
		current->matches(frame, match, callInstance, arg);

		JP_TRACE("  match ended", match.m_Type);
		if (match.m_Type == JPMatch::_exact)
		{
			bestMatch = match;
			m_LastCache = match;
			return true;
		}
		if (match.m_Type < JPMatch::_implicit)
			continue;

		// If this is the first match then make it the best.
		if (bestMatch.m_Overload == 0)
		{
			bestMatch = match;
			continue;
		}

		// If the best does not hide the other, than we have ambiguity.
		if (!(bestMatch.m_Overload->checkMoreSpecificThan(current)))
		{
			// See if we can match based on instance
			if (callInstance == !current->isStatic())
			{
				// if current matches instance and best does not switch
				if (callInstance == bestMatch.m_Overload->isStatic())
				{
					bestMatch = match;
					continue;
				}
			} else
			{
				// if best matches instance and current does not, no ambiguity
				if (callInstance == !bestMatch.m_Overload->isStatic())
				{
					continue;
				}
			}

			JP_TRACE("Adding to ambiguous list");
			ambiguous.push_back(*it);
		}
	}

	// If we have an ambiguous overload report an error.
	if (!ambiguous.empty())
	{
		if (!raise)
			return false;
		ambiguous.push_back(bestMatch.m_Overload);

		// We have two possible overloads so we declare an error
		std::stringstream ss;
		if (JPModifier::isConstructor(m_Modifiers))
			ss << "Ambiguous overloads found for constructor " << m_Class->getCanonicalName() << "(";
		else
			ss << "Ambiguous overloads found for " << m_Class->getCanonicalName() << "." << getName() << "(";
		size_t start = callInstance ? 1 : 0;
		for (size_t i = start; i < arg.size(); ++i)
		{
			if (i != start)
				ss << ",";
			ss << Py_TYPE(arg[i])->tp_name;
		}
		ss << ")" << " between:" << std::endl;
		for (vector<JPMethod*>::iterator it = ambiguous.begin(); it != ambiguous.end(); ++it)
		{
			ss << "\t" << (*it)->toString() << std::endl;
		}
		JP_RAISE(PyExc_TypeError, ss.str());
		JP_TRACE(ss.str());
	}

	// If we can't find a matching overload throw an error.
	if (!bestMatch.m_Overload)
	{
		if (!raise)
			return false;
		std::stringstream ss;
		if (JPModifier::isConstructor(m_Modifiers))
			ss << "No matching overloads found for constructor " << m_Class->getCanonicalName() << "(";
		else
			ss << "No matching overloads found for " << m_Class->getCanonicalName() << "." << getName() << "(";
		size_t start = callInstance ? 1 : 0;
		for (size_t i = start; i < arg.size(); ++i)
		{
			if (i != start)
				ss << ",";
			ss << Py_TYPE(arg[i])->tp_name;
		}
		ss << ")" << ", options are:" << std::endl;
		for (JPMethodList::iterator it = m_Overloads.begin();
				it != m_Overloads.end();
				++it)
		{
			JPMethod* current = *it;
			ss << "\t" << current->toString();
			ss << std::endl;
		}
		JP_RAISE(PyExc_TypeError, ss.str());
	}

	// Set up a cache to bypass repeated calls.
	if (bestMatch.m_Type == JPMatch::_implicit)
	{
		m_LastCache = bestMatch;
	}

	JP_TRACE("Best match", bestMatch.m_Overload->toString());
	return true;
	JP_TRACE_OUT;
}

JPPyObject JPMethodDispatch::invoke(JPJavaFrame& frame, JPPyObjectVector& args, bool instance)
{
	JP_TRACE_IN("JPMethodDispatch::invoke");
	JPMethodMatch match(frame, args, instance);
	findOverload(frame, match, args, instance, true);
	return match.m_Overload->invoke(frame, match, args, instance);
	JP_TRACE_OUT;
}

JPValue JPMethodDispatch::invokeConstructor(JPJavaFrame& frame, JPPyObjectVector& args)
{
	JP_TRACE_IN("JPMethodDispatch::invokeConstructor");
	JPMethodMatch match(frame, args, false);
	findOverload(frame, match, args, false, true);
	return match.m_Overload->invokeConstructor(frame, match, args);
	JP_TRACE_OUT;
}

bool JPMethodDispatch::matches(JPJavaFrame& frame, JPPyObjectVector& args, bool instance)
{
	JP_TRACE_IN("JPMethodDispatch::invoke");
	JPMethodMatch match(frame, args, instance);
	return findOverload(frame, match, args, instance, false);
	JP_TRACE_OUT;  // GCOVR_EXCL_LINE
}

string JPMethodDispatch::matchReport(JPPyObjectVector& args)
{
	stringstream res;
	res << "Match report for method " << m_Name << ", has " << m_Overloads.size() << " overloads." << endl;

	for (JPMethodList::iterator cur = m_Overloads.begin(); cur != m_Overloads.end(); cur++)
	{
		JPMethod* current = *cur;
		res << "  " << current->matchReport(args);
	}
	return res.str();
}

<|endoftext|>


<commit_before>/*
 * This file is part of OpenModelica.
 *
 * Copyright (c) 1998-CurrentYear, Linköping University,
 * Department of Computer and Information Science,
 * SE-58183 Linköping, Sweden.
 *
 * All rights reserved.
 *
 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3
 * AND THIS OSMC PUBLIC LICENSE (OSMC-PL).
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THE OSMC PUBLIC LICENSE.
 *
 * The OpenModelica software and the Open Source Modelica
 * Consortium (OSMC) Public License (OSMC-PL) are obtained
 * from Linköping University, either from the above address,
 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
 * http://www.openmodelica.org, and in the OpenModelica distribution.
 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without
 * even the implied warranty of  MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
 * OF OSMC-PL.
 *
 * See the full OSMC Public License conditions for more details.
 *
 */

/*
 * HopsanGUI
 * Fluid and Mechatronic Systems, Department of Management and Engineering, Linköping University
 * Main Authors 2009-2010:  Robert Braun, Björn Eriksson, Peter Nordin
 * Contributors 2009-2010:  Mikael Axin, Alessandro Dell'Amico, Karl Pettersson, Ingo Staack
 */

//$Id$

#include "GUIPort.h"
#include "plotwidget.h"
#include "mainwindow.h"

#include <QtGui>

//! Constructor.
//! @param portName The name of the port
//! @param x the x-coord. of where the port should be placed.
//! @param y the y-coord. of where the port should be placed.
//! @param rot how the port should be rotated.
//! @param iconPath a string with the path to the svg-figure representing the port.
//! @param parent the port's parent, the component it is a part of.
GUIPort::GUIPort(QString portName, qreal xpos, qreal ypos, PortAppearance* pPortAppearance, GUIObject *pParent, GUIRootSystem *pGUIRootSystem)
    : QGraphicsSvgItem(pPortAppearance->iconPath, pParent)
{
    mpParentGraphicsView = pParent->mpParentGraphicsView;
    mpParentGuiObject = pParent;
    mpPortAppearance = pPortAppearance;
    mpGUIRootSystem = pGUIRootSystem; //Use this to indicate system port

    this->name = portName;

    //setTransformOriginPoint(boundingRect().width()/2,boundingRect().height()/2);
    setTransformOriginPoint(boundingRect().center());

    mXpos = xpos;
    mYpos = ypos;

    updatePosition();

//    pRectParent = parent;
    this->setAcceptHoverEvents(true);

    //QBrush brush(Qt::green);
    //this->setBrush(brush);

    mpPortLabel = new QGraphicsTextItem(this);
    QString label("
");
    label.append(this->getName()).append("
");
    mpPortLabel->setHtml(label);
    mpPortLabel->setTextInteractionFlags(Qt::NoTextInteraction);
    mpPortLabel->setPos(7.0,7.0);
    mpPortLabel->hide();

    //! @todo this kind of harcoded stuff should not be here, fix the problem in some other way
    if(this->getPortType() == "POWERPORT")
    {
        this->setRotation(0.0);
        mpPortLabel->setRotation(0.0);
    }
    else
    {
        this->setRotation(mpPortAppearance->rot);
        mpPortLabel->setRotation(-mpPortAppearance->rot);
    }

    mMag = 1.6180339887;
    mIsMag = false;
    isConnected = false;

    MainWindow *pMainWindow = mpParentGuiObject->mpParentGraphicsScene->mpParentProjectTab->mpParentProjectTabWidget->mpParentMainWindow;
    connect(this,SIGNAL(portClicked(GUIPort*)),this->getParentView(),SLOT(addConnector(GUIPort*)));
    connect(pMainWindow->hidePortsAction,SIGNAL(triggered(bool)),this, SLOT(hideIfNotConnected(bool)));
    //connect(pMainWindow->showPortsAction,SIGNAL(triggered()),this, SLOT(showIfNotConnected()));
}

GUIPort::~GUIPort()
{
}

//! Magnify the port with a class mebmer factor 'mMag'. Is used i.e. at hovering over disconnected port.
//! @param blowup says if the port should be magnified or not.
void GUIPort::magnify(bool blowup)
{
    if ((!blowup) && (mIsMag))
    {
        this->moveBy((mMag-1)*boundingRect().width()/2, (mMag-1)*boundingRect().height()/2);
        this->scale(1/mMag,1/mMag);
        this->mpPortLabel->scale(mMag,mMag);
        mIsMag = false;
    }
    else if ((blowup) && (!mIsMag))
    {
        this->scale(mMag, mMag);
        this->moveBy(-(mMag-1)*boundingRect().width()/2, -(mMag-1)*boundingRect().height()/2);
        this->mpPortLabel->scale(1/mMag,1/mMag);
        mIsMag = true;
    }
}

//! Defines what happens when mouse cursor begins to hover a port.
//! @param *event defines the mouse event.
void GUIPort::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    QGraphicsSvgItem::hoverEnterEvent(event);

    this->setCursor(Qt::CrossCursor);
    QBrush brush(Qt::blue);
    std::cout << "GUIPort.cpp: " << "hovering over port" << std::endl;
    magnify(true);

    mpPortLabel->setRotation(-this->mpParentGuiObject->rotation()-this->rotation());
    //qDebug() << "label: " << mpPortLabel->rotation() << " this: " << this->rotation();
    this->setZValue(1.0);
    mpPortLabel->show();
}

void GUIPort::updatePosition()
{
    if(mpParentGuiObject->rotation() == 0)
        setPos(mXpos-this->boundingRect().width()/2.0, mYpos-this->boundingRect().height()/2.0);
    else if(mpParentGuiObject->rotation() == 90)
        setPos(mXpos-this->boundingRect().width()/2.0, mYpos+this->boundingRect().height()/2.0);
    else if(mpParentGuiObject->rotation() == 180)
        setPos(mXpos+this->boundingRect().width()/2.0, mYpos+this->boundingRect().height()/2.0);
    else
        setPos(mXpos+this->boundingRect().width()/2.0, mYpos-this->boundingRect().height()/2.0);
}

//! Defines what happens when mouse cursor stops hovering a port.
//! @param *event defines the mouse event.
void GUIPort::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    QGraphicsSvgItem::hoverLeaveEvent(event);

    QBrush brush(Qt::green);
    //this->setBrush(brush);
    this->setCursor(Qt::ArrowCursor);
    magnify(false);

    mpPortLabel->hide();
    this->setZValue(0.0);
}

//! Defines what happens when clicking on a port.
//! @param *event defines the mouse event.
void GUIPort::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    //QGraphicsItem::mousePressEvent(event); //Don't work if this is called
    if (event->button() == Qt::LeftButton)
    {
        std::cout << "GUIPort.cpp: " << "portClick emitted\n";
        emit portClicked(this);
    }
    else if (event->button() == Qt::RightButton)
    {
        std::cout << "GUIPort.cpp: " << "RightClick" << std::endl;
    }
    magnify(false);
}

void GUIPort::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    std::cout << "GUIPort.cpp: " << "contextMenuEvent" << std::endl;

    if ((!this->isConnected) || (this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getTimeVector(getGUIComponentName(), this->getName()).empty()))
    {
        event->ignore();
    }
    else
    {
        QMenu menu;
        //! @todo this bellow is complete madness. hardcoded hopsan specific stuff, must be rewritten, not sure if it should even be here
        //! @todo we do not need hardcoded stuff we can ask the core about what variables are available
        if (this->getNodeType() =="NodeHydraulic")
        {
            QAction *plotPressureAction = menu.addAction("Plot pressure");
            QAction *plotFlowAction = menu.addAction("Plot flow");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotFlowAction)
            {
                plot("MassFlow");
            }
            if (selectedAction == plotPressureAction)
            {
                plot("Pressure");
            }
        }
        if (this->getNodeType() =="NodeMechanic")
        {
            QAction *plotVelocityAction = menu.addAction("Plot velocity");
            QAction *plotForceAction = menu.addAction("Plot force");
            QAction *plotPositionAction = menu.addAction("Plot position");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotVelocityAction)
            {
                plot("Velocity");
            }
            if (selectedAction == plotForceAction)
            {
                plot("Force");
            }
            if (selectedAction == plotPositionAction)
            {
                plot("Position");
            }
        }
        if (this->getNodeType() =="NodeSignal")
        {
            QAction *plotSignalAction = menu.addAction("Plot signal value");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotSignalAction)
            {
                plot("Value");
            }
        }
    }
}

//! Returns a pointer to the GraphicsView that the port belongs to.
GraphicsView *GUIPort::getParentView()
{
    return mpParentGraphicsView;
}

//! Returns a pointer to the GUIComponent the port belongs to.
GUIObject *GUIPort::getGuiObject()
{
    return mpParentGuiObject;
}

//! Plots the varable number 'nVar' in the node the port is connected to.
//! @param nVar tells which variable to plot.
//! @todo If dataUnit not supplied no unit will be shown, we should maybe lookup the unit if not supplid, or allways look it up, or demand that it is supplied
void GUIPort::plot(QString dataName, QString dataUnit) //En del vansinne i denna metoden...
{
    std::cout << "GUIPort.cpp: " << "Plot()" << std::endl;

    QVector<double> time = QVector<double>::fromStdVector(mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getTimeVector(getGUIComponentName(), this->getName()));
    QVector<double> y;
    mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getPlotData(getGUIComponentName(), this->getName(), dataName, y);

    qDebug() << "Time size: " << time.size() << " last time: " << *time.end() << " " << "y.size(): " << y.size();
    qDebug() << "time[0]: " << time[0] << " time[last-1]: " << time[time.size()-2] << " time[last]: " << time[time.size()-1];

    for (int i = 0; i<time.size(); ++i)
    {
        //qDebug() << time[i];
    }

    qDebug() << "y[0]: " << y[0] << " y[last-1]: " << y[y.size()-2] << " y[last]: " << y[y.size()-1];

    QString title;
    QString xlabel;
    QString ylabel;

    title.append(dataName);
    ylabel.append(dataName + ", [" + dataUnit + "]");

    //! @todo need to comment this out  for now  fix later
    //title.append(" at component: ").append(QString::fromStdString(mpParentComponent->mpCoreComponent->getName())).append(", port: ").append(QString::fromStdString(mpCorePort->getPortName()));
    xlabel.append("Time, [s]");

    //PlotWidget *newPlot = new PlotWidget(time,y,mpParentGuiObject->mpParentGraphicsView);
    PlotWidget *newPlot = new PlotWidget(time,y,mpParentGuiObject->mpParentGraphicsView->mpParentProjectTab->mpParentProjectTabWidget->mpParentMainWindow);

    //newPlot->mpVariablePlot->setTitle(title);
    newPlot->mpCurve->setTitle(title);
    newPlot->mpVariablePlot->setAxisTitle(VariablePlot::yLeft, ylabel);
    newPlot->mpVariablePlot->setAxisTitle(VariablePlot::xBottom, xlabel);
    newPlot->mpVariablePlot->insertLegend(new QwtLegend(), QwtPlot::TopLegend);

    newPlot->show();
}

//! Returns the number of the port by calling the equivalent function in the parent component.
int GUIPort::getPortNumber()
{
    return this->getGuiObject()->getPortNumber(this);
}

//! Wrapper for the Core getPortTypeString() function
QString GUIPort::getPortType()
{
    return this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getPortType(getGUIComponentName(), this->getName());
}

//! Wrapper for the Core getNodeType() function
QString GUIPort::getNodeType()
{
    return this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getNodeType(getGUIComponentName(), this->getName());
}

PortAppearance::portDirectionType GUIPort::getPortDirection()
{
    return mpPortAppearance->direction;
}

void GUIPort::setPortDirection(PortAppearance::portDirectionType direction)
{
    mpPortAppearance->direction = direction;
}

QString GUIPort::getName()
{
    return this->name;
}

void GUIPort::setDisplayName(const QString name)
{
    this->name = name;
    QString label("
");
    label.append(this->name).append("
");
    mpPortLabel->setHtml(label);
}

//! Get the name of the GUIComponent or GUISubsystem that the port is connected to, This is not necessarily the same as the parent GUIObject name (SystemPorts)
//! @todo this is a very ugly way of handeling system ports should try to think of something better
QString GUIPort::getGUIComponentName()
{
    qDebug() << "apa";
    if (mpGUIRootSystem == 0)
    {
        qDebug() << "apa2";
        qDebug() << "return guiobject name: " << mpParentGuiObject->getName();
        return mpParentGuiObject->getName();
    }
    else
    {
        qDebug() << "apa3";
        qDebug() << "return root name: " << mpGUIRootSystem->getName();
        return mpGUIRootSystem->getName();
    }
}

void GUIPort::hideIfNotConnected(bool justDoIt)
{
    if(!isConnected and justDoIt)
    {
        this->hide();
    }
    else if(!isConnected and !justDoIt)
    {
        this->show();
    }
}
<commit_msg>Cleared some "apa"-debugs<commit_after>/*
 * This file is part of OpenModelica.
 *
 * Copyright (c) 1998-CurrentYear, Linköping University,
 * Department of Computer and Information Science,
 * SE-58183 Linköping, Sweden.
 *
 * All rights reserved.
 *
 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF GPL VERSION 3
 * AND THIS OSMC PUBLIC LICENSE (OSMC-PL).
 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THE OSMC PUBLIC LICENSE.
 *
 * The OpenModelica software and the Open Source Modelica
 * Consortium (OSMC) Public License (OSMC-PL) are obtained
 * from Linköping University, either from the above address,
 * from the URLs: http://www.ida.liu.se/projects/OpenModelica or
 * http://www.openmodelica.org, and in the OpenModelica distribution.
 * GNU version 3 is obtained from: http://www.gnu.org/copyleft/gpl.html.
 *
 * This program is distributed WITHOUT ANY WARRANTY; without
 * even the implied warranty of  MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS
 * OF OSMC-PL.
 *
 * See the full OSMC Public License conditions for more details.
 *
 */

/*
 * HopsanGUI
 * Fluid and Mechatronic Systems, Department of Management and Engineering, Linköping University
 * Main Authors 2009-2010:  Robert Braun, Björn Eriksson, Peter Nordin
 * Contributors 2009-2010:  Mikael Axin, Alessandro Dell'Amico, Karl Pettersson, Ingo Staack
 */

//$Id$

#include "GUIPort.h"
#include "plotwidget.h"
#include "mainwindow.h"

#include <QtGui>

//! Constructor.
//! @param portName The name of the port
//! @param x the x-coord. of where the port should be placed.
//! @param y the y-coord. of where the port should be placed.
//! @param rot how the port should be rotated.
//! @param iconPath a string with the path to the svg-figure representing the port.
//! @param parent the port's parent, the component it is a part of.
GUIPort::GUIPort(QString portName, qreal xpos, qreal ypos, PortAppearance* pPortAppearance, GUIObject *pParent, GUIRootSystem *pGUIRootSystem)
    : QGraphicsSvgItem(pPortAppearance->iconPath, pParent)
{
    mpParentGraphicsView = pParent->mpParentGraphicsView;
    mpParentGuiObject = pParent;
    mpPortAppearance = pPortAppearance;
    mpGUIRootSystem = pGUIRootSystem; //Use this to indicate system port

    this->name = portName;

    //setTransformOriginPoint(boundingRect().width()/2,boundingRect().height()/2);
    setTransformOriginPoint(boundingRect().center());

    mXpos = xpos;
    mYpos = ypos;

    updatePosition();

//    pRectParent = parent;
    this->setAcceptHoverEvents(true);

    //QBrush brush(Qt::green);
    //this->setBrush(brush);

    mpPortLabel = new QGraphicsTextItem(this);
    QString label("
");
    label.append(this->getName()).append("
");
    mpPortLabel->setHtml(label);
    mpPortLabel->setTextInteractionFlags(Qt::NoTextInteraction);
    mpPortLabel->setPos(7.0,7.0);
    mpPortLabel->hide();

    //! @todo this kind of harcoded stuff should not be here, fix the problem in some other way
    if(this->getPortType() == "POWERPORT")
    {
        this->setRotation(0.0);
        mpPortLabel->setRotation(0.0);
    }
    else
    {
        this->setRotation(mpPortAppearance->rot);
        mpPortLabel->setRotation(-mpPortAppearance->rot);
    }

    mMag = 1.6180339887;
    mIsMag = false;
    isConnected = false;

    MainWindow *pMainWindow = mpParentGuiObject->mpParentGraphicsScene->mpParentProjectTab->mpParentProjectTabWidget->mpParentMainWindow;
    connect(this,SIGNAL(portClicked(GUIPort*)),this->getParentView(),SLOT(addConnector(GUIPort*)));
    connect(pMainWindow->hidePortsAction,SIGNAL(triggered(bool)),this, SLOT(hideIfNotConnected(bool)));
    //connect(pMainWindow->showPortsAction,SIGNAL(triggered()),this, SLOT(showIfNotConnected()));
}

GUIPort::~GUIPort()
{
}

//! Magnify the port with a class mebmer factor 'mMag'. Is used i.e. at hovering over disconnected port.
//! @param blowup says if the port should be magnified or not.
void GUIPort::magnify(bool blowup)
{
    if ((!blowup) && (mIsMag))
    {
        this->moveBy((mMag-1)*boundingRect().width()/2, (mMag-1)*boundingRect().height()/2);
        this->scale(1/mMag,1/mMag);
        this->mpPortLabel->scale(mMag,mMag);
        mIsMag = false;
    }
    else if ((blowup) && (!mIsMag))
    {
        this->scale(mMag, mMag);
        this->moveBy(-(mMag-1)*boundingRect().width()/2, -(mMag-1)*boundingRect().height()/2);
        this->mpPortLabel->scale(1/mMag,1/mMag);
        mIsMag = true;
    }
}

//! Defines what happens when mouse cursor begins to hover a port.
//! @param *event defines the mouse event.
void GUIPort::hoverEnterEvent(QGraphicsSceneHoverEvent *event)
{
    QGraphicsSvgItem::hoverEnterEvent(event);

    this->setCursor(Qt::CrossCursor);
    QBrush brush(Qt::blue);
    std::cout << "GUIPort.cpp: " << "hovering over port" << std::endl;
    magnify(true);

    mpPortLabel->setRotation(-this->mpParentGuiObject->rotation()-this->rotation());
    //qDebug() << "label: " << mpPortLabel->rotation() << " this: " << this->rotation();
    this->setZValue(1.0);
    mpPortLabel->show();
}

void GUIPort::updatePosition()
{
    if(mpParentGuiObject->rotation() == 0)
        setPos(mXpos-this->boundingRect().width()/2.0, mYpos-this->boundingRect().height()/2.0);
    else if(mpParentGuiObject->rotation() == 90)
        setPos(mXpos-this->boundingRect().width()/2.0, mYpos+this->boundingRect().height()/2.0);
    else if(mpParentGuiObject->rotation() == 180)
        setPos(mXpos+this->boundingRect().width()/2.0, mYpos+this->boundingRect().height()/2.0);
    else
        setPos(mXpos+this->boundingRect().width()/2.0, mYpos-this->boundingRect().height()/2.0);
}

//! Defines what happens when mouse cursor stops hovering a port.
//! @param *event defines the mouse event.
void GUIPort::hoverLeaveEvent(QGraphicsSceneHoverEvent *event)
{
    QGraphicsSvgItem::hoverLeaveEvent(event);

    QBrush brush(Qt::green);
    //this->setBrush(brush);
    this->setCursor(Qt::ArrowCursor);
    magnify(false);

    mpPortLabel->hide();
    this->setZValue(0.0);
}

//! Defines what happens when clicking on a port.
//! @param *event defines the mouse event.
void GUIPort::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
    //QGraphicsItem::mousePressEvent(event); //Don't work if this is called
    if (event->button() == Qt::LeftButton)
    {
        std::cout << "GUIPort.cpp: " << "portClick emitted\n";
        emit portClicked(this);
    }
    else if (event->button() == Qt::RightButton)
    {
        std::cout << "GUIPort.cpp: " << "RightClick" << std::endl;
    }
    magnify(false);
}

void GUIPort::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
{
    std::cout << "GUIPort.cpp: " << "contextMenuEvent" << std::endl;

    if ((!this->isConnected) || (this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getTimeVector(getGUIComponentName(), this->getName()).empty()))
    {
        event->ignore();
    }
    else
    {
        QMenu menu;
        //! @todo this bellow is complete madness. hardcoded hopsan specific stuff, must be rewritten, not sure if it should even be here
        //! @todo we do not need hardcoded stuff we can ask the core about what variables are available
        if (this->getNodeType() =="NodeHydraulic")
        {
            QAction *plotPressureAction = menu.addAction("Plot pressure");
            QAction *plotFlowAction = menu.addAction("Plot flow");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotFlowAction)
            {
                plot("MassFlow");
            }
            if (selectedAction == plotPressureAction)
            {
                plot("Pressure");
            }
        }
        if (this->getNodeType() =="NodeMechanic")
        {
            QAction *plotVelocityAction = menu.addAction("Plot velocity");
            QAction *plotForceAction = menu.addAction("Plot force");
            QAction *plotPositionAction = menu.addAction("Plot position");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotVelocityAction)
            {
                plot("Velocity");
            }
            if (selectedAction == plotForceAction)
            {
                plot("Force");
            }
            if (selectedAction == plotPositionAction)
            {
                plot("Position");
            }
        }
        if (this->getNodeType() =="NodeSignal")
        {
            QAction *plotSignalAction = menu.addAction("Plot signal value");
            QAction *selectedAction = menu.exec(event->screenPos());

            if (selectedAction == plotSignalAction)
            {
                plot("Value");
            }
        }
    }
}

//! Returns a pointer to the GraphicsView that the port belongs to.
GraphicsView *GUIPort::getParentView()
{
    return mpParentGraphicsView;
}

//! Returns a pointer to the GUIComponent the port belongs to.
GUIObject *GUIPort::getGuiObject()
{
    return mpParentGuiObject;
}

//! Plots the varable number 'nVar' in the node the port is connected to.
//! @param nVar tells which variable to plot.
//! @todo If dataUnit not supplied no unit will be shown, we should maybe lookup the unit if not supplid, or allways look it up, or demand that it is supplied
void GUIPort::plot(QString dataName, QString dataUnit) //En del vansinne i denna metoden...
{
    std::cout << "GUIPort.cpp: " << "Plot()" << std::endl;

    QVector<double> time = QVector<double>::fromStdVector(mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getTimeVector(getGUIComponentName(), this->getName()));
    QVector<double> y;
    mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getPlotData(getGUIComponentName(), this->getName(), dataName, y);

    qDebug() << "Time size: " << time.size() << " last time: " << *time.end() << " " << "y.size(): " << y.size();
    qDebug() << "time[0]: " << time[0] << " time[last-1]: " << time[time.size()-2] << " time[last]: " << time[time.size()-1];

    for (int i = 0; i<time.size(); ++i)
    {
        //qDebug() << time[i];
    }

    qDebug() << "y[0]: " << y[0] << " y[last-1]: " << y[y.size()-2] << " y[last]: " << y[y.size()-1];

    QString title;
    QString xlabel;
    QString ylabel;

    title.append(dataName);
    ylabel.append(dataName + ", [" + dataUnit + "]");

    //! @todo need to comment this out  for now  fix later
    //title.append(" at component: ").append(QString::fromStdString(mpParentComponent->mpCoreComponent->getName())).append(", port: ").append(QString::fromStdString(mpCorePort->getPortName()));
    xlabel.append("Time, [s]");

    //PlotWidget *newPlot = new PlotWidget(time,y,mpParentGuiObject->mpParentGraphicsView);
    PlotWidget *newPlot = new PlotWidget(time,y,mpParentGuiObject->mpParentGraphicsView->mpParentProjectTab->mpParentProjectTabWidget->mpParentMainWindow);

    //newPlot->mpVariablePlot->setTitle(title);
    newPlot->mpCurve->setTitle(title);
    newPlot->mpVariablePlot->setAxisTitle(VariablePlot::yLeft, ylabel);
    newPlot->mpVariablePlot->setAxisTitle(VariablePlot::xBottom, xlabel);
    newPlot->mpVariablePlot->insertLegend(new QwtLegend(), QwtPlot::TopLegend);

    newPlot->show();
}

//! Returns the number of the port by calling the equivalent function in the parent component.
int GUIPort::getPortNumber()
{
    return this->getGuiObject()->getPortNumber(this);
}

//! Wrapper for the Core getPortTypeString() function
QString GUIPort::getPortType()
{
    return this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getPortType(getGUIComponentName(), this->getName());
}

//! Wrapper for the Core getNodeType() function
QString GUIPort::getNodeType()
{
    return this->mpParentGraphicsView->mpParentProjectTab->mGUIRootSystem.getNodeType(getGUIComponentName(), this->getName());
}

PortAppearance::portDirectionType GUIPort::getPortDirection()
{
    return mpPortAppearance->direction;
}

void GUIPort::setPortDirection(PortAppearance::portDirectionType direction)
{
    mpPortAppearance->direction = direction;
}

QString GUIPort::getName()
{
    return this->name;
}

void GUIPort::setDisplayName(const QString name)
{
    this->name = name;
    QString label("
");
    label.append(this->name).append("
");
    mpPortLabel->setHtml(label);
}

//! Get the name of the GUIComponent or GUISubsystem that the port is connected to, This is not necessarily the same as the parent GUIObject name (SystemPorts)
//! @todo this is a very ugly way of handeling system ports should try to think of something better
QString GUIPort::getGUIComponentName()
{
    if (mpGUIRootSystem == 0)
    {
        qDebug() << "return guiobject name: " << mpParentGuiObject->getName();
        return mpParentGuiObject->getName();
    }
    else
    {
        qDebug() << "return root name: " << mpGUIRootSystem->getName();
        return mpGUIRootSystem->getName();
    }
}

void GUIPort::hideIfNotConnected(bool justDoIt)
{
    if(!isConnected and justDoIt)
    {
        this->hide();
    }
    else if(!isConnected and !justDoIt)
    {
        this->show();
    }
}
<|endoftext|>


<commit_before>#include "Tle.h"

#include <cassert>
#include <cstdlib>

Tle::Tle(const std::string& line_one, const std::string& line_two) {

    name_.erase();
    line_one_ = line_one;
    line_two_ = line_two;

    Initialize();
}

Tle::Tle(const std::string& name, const std::string& line_one, const std::string& line_two) {

    name_ = name;
    line_one_ = line_one;
    line_two_ = line_two;

    Initialize();
}

Tle::Tle(const Tle& tle) {

    name_ = tle.name_;
    line_one_ = tle.line_one_;
    line_two_ = tle.line_two_;

    norad_number_ = tle.norad_number_;
    international_designator_ = tle.international_designator_;
    epoch_ = tle.epoch_;
    mean_motion_dot_ = tle.mean_motion_dot_;
    mean_motion_dot2_ = tle.mean_motion_dot2_;
    bstar_ = tle.bstar_;
    inclination_ = tle.inclination_;
    right_ascending_node_ = tle.right_ascending_node_;
    eccentricity_ = tle.eccentricity_;
    argument_perigee_ = tle.argument_perigee_;
    mean_anomaly_ = tle.mean_anomaly_;
    mean_motion_ = tle.mean_motion_;
    orbit_number_ = tle.orbit_number_;
}

Tle::~Tle() {
}

/*
 * convert a tle raw string into an exponent string
 */
std::string Tle::ExpToDecimal(const std::string& str) {

    static const int START_SIGN = 0;
    static const int LENGTH_SIGN = 1;
    static const int START_MANTISSA = 1;
    static const int LENGTH_MANTISSA = 5;
    static const int START_EXP = 6;
    static const int LENGTH_EXP = 2;

    assert(8 == str.length());

    std::string value = str.substr(START_SIGN, LENGTH_SIGN);
    value += ".";
    value += str.substr(START_MANTISSA, LENGTH_MANTISSA);
    value += "e";
    value += str.substr(START_EXP, LENGTH_EXP);

    return value;
}

/*
 * extract all variables
 */
void Tle::Initialize() {

    std::string temp;

    /*
     * trim whitespace
     */
    TrimLeft(name_);
    TrimRight(name_);
    TrimLeft(line_one_);
    TrimRight(line_one_);
    TrimLeft(line_two_);
    TrimRight(line_two_);

    /*
     * check the two lines are valid
     */
    assert(IsValidPair(line_one_, line_two_));

    /*
     * line 1
     */

    temp = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM).c_str();
    norad_number_ = atoi(temp.c_str());
    /*
     * if blank use norad number
     */
    if (name_.empty())
        name_ = temp;

    international_designator_ = line_one_.substr(TLE1_COL_INTLDESC_A, TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);

    int year = atoi(line_one_.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A).c_str());
    double day = atof(line_one_.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B).c_str());
    /*
     * generate julian date for epoch
     */
    if (year < 57)
        year += 2000;
    else
        year += 1900;

    epoch_ = Julian(year, day);

    if (line_one_[TLE1_COL_MEANMOTIONDT] == '-') {
        temp = "-0";
    } else
        temp = "0";
    temp += line_one_.substr(TLE1_COL_MEANMOTIONDT + 1, TLE1_LEN_MEANMOTIONDT);
    mean_motion_dot_ = atof(temp.c_str());

    temp = ExpToDecimal(line_one_.substr(TLE1_COL_MEANMOTIONDT2, TLE1_LEN_MEANMOTIONDT2));
    mean_motion_dot2_ = atof(temp.c_str());

    temp = ExpToDecimal(line_one_.substr(TLE1_COL_BSTAR, TLE1_LEN_BSTAR).c_str());
    bstar_ = atof(temp.c_str());

    /*
     * line 2
     */

    temp = line_two_.substr(TLE2_COL_INCLINATION, TLE2_LEN_INCLINATION);
    TrimLeft(temp);
    inclination_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_RAASCENDNODE, TLE2_LEN_RAASCENDNODE);
    TrimLeft(temp);
    right_ascending_node_ = atof(temp.c_str());

    temp = "0.";
    temp += line_two_.substr(TLE2_COL_ECCENTRICITY, TLE2_LEN_ECCENTRICITY);
    eccentricity_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_ARGPERIGEE, TLE2_LEN_ARGPERIGEE);
    TrimLeft(temp);
    argument_perigee_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_MEANANOMALY, TLE2_LEN_MEANANOMALY);
    TrimLeft(temp);
    mean_anomaly_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_MEANMOTION, TLE2_LEN_MEANMOTION);
    TrimLeft(temp);
    mean_motion_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_REVATEPOCH, TLE2_LEN_REVATEPOCH);
    TrimLeft(temp);
    orbit_number_ = atoi(temp.c_str());
}

/*
 * check the two lines have matching norad numbers
 * and that the lines themselves are valid
 */
bool Tle::IsValidPair(const std::string& line1, const std::string& line2) {

    if (atoi(line1.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM).c_str()) !=
            atoi(line2.substr(TLE2_COL_NORADNUM, TLE2_LEN_NORADNUM).c_str()))
        return false;

    if (!IsValidLine(line1, 1))
        return false;

    if (!IsValidLine(line2, 2))
        return false;

    return true;
}

/*
 * validate a line
 */
bool Tle::IsValidLine(const std::string& str, const unsigned char line_number) {

    static const std::string line1_pattern = "1 NNNNNC NNNNAAAA NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN";
    static const std::string line2_pattern = "2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN";

    /*
     * validate line against the pattern
     */
    if (1 == line_number) {
        if (!ValidateLine(str, line1_pattern))
            return false;
    } else if (2 == line_number) {
        if (!ValidateLine(str, line2_pattern))
            return false;
    }

    /*
     * last char in string is modulo 10 checksum
     * edited out as checksum isnt consistent
     *
     * int chk = CheckSum(str);
     * if (chk != (str[TLE_LEN_LINE_DATA - 1] - '0'))
     *   return false;
     */

    return true;
}

/*
 * validate line given a pattern
 */
bool Tle::ValidateLine(const std::string& line, const std::string& pattern) {

    /*
     * check length of lines match
     */
    if (line.length() < pattern.length()) {
        return false;
    }

    std::string::const_iterator pattern_itr = pattern.begin();
    std::string::const_iterator line_itr = line.begin();

    while (pattern_itr != pattern.end()) {

        if (isdigit(*pattern_itr) || *pattern_itr == ' ' ||
                *pattern_itr == '.') {

            /*
             * these characters should match exactly
             */
            if (*pattern_itr != *line_itr)
                return false;

        } else if (*pattern_itr == 'N') {

            /*
             * if pattern value is 'N' then either a number or a ' '
             */
            if (!isdigit(*line_itr) && *line_itr != ' ')
                return false;

        } else if (*pattern_itr == '+') {

            /*
             * if pattern value is '+' then either a '+' or a ' '
             */
            if (*line_itr != '+' && *line_itr != '-' && *line_itr != ' ')
                return false;

        } else if (*pattern_itr == '-') {

            /*
             * if pattern value is '+' or a '+'
             */
            if (*line_itr != '+' && *line_itr != '-')
                return false;
        }

        pattern_itr++;
        line_itr++;
    }

    return true;
}

/*
 * compute checksum
 */
int Tle::CheckSum(const std::string& str) {

    size_t len = str.size() - 1;
    int xsum = 0;

    for (size_t i = 0; i < len; i++) {

        char ch = str[i];

        if (isdigit(ch))
            xsum += (ch - '0');
        else
            if (ch == '-')
            xsum++;
    }

    return (xsum % 10);
}

/*
 * trim left of string
 */
void Tle::TrimLeft(std::string& str) {

    std::string whitespaces(" \t\f\n\r");

    if (!str.empty()) {
        std::string::size_type pos = str.find_first_not_of(whitespaces);

        if (pos != std::string::npos)
            str.erase(0, pos);
        else
            str.clear();
    }
}

/*
 * trim right of string
 */
void Tle::TrimRight(std::string& str) {

    std::string whitespaces(" \t\f\n\r");

    if (!str.empty()) {
        std::string::size_type pos = str.find_last_not_of(whitespaces);

        if (pos != std::string::npos)
            str.erase(pos + 1);
        else
            str.clear();
    }
}

<commit_msg>Changes to tle rules<commit_after>#include "Tle.h"

#include <cassert>
#include <cstdlib>

Tle::Tle(const std::string& line_one, const std::string& line_two) {

    name_.erase();
    line_one_ = line_one;
    line_two_ = line_two;

    Initialize();
}

Tle::Tle(const std::string& name, const std::string& line_one, const std::string& line_two) {

    name_ = name;
    line_one_ = line_one;
    line_two_ = line_two;

    Initialize();
}

Tle::Tle(const Tle& tle) {

    name_ = tle.name_;
    line_one_ = tle.line_one_;
    line_two_ = tle.line_two_;

    norad_number_ = tle.norad_number_;
    international_designator_ = tle.international_designator_;
    epoch_ = tle.epoch_;
    mean_motion_dot_ = tle.mean_motion_dot_;
    mean_motion_dot2_ = tle.mean_motion_dot2_;
    bstar_ = tle.bstar_;
    inclination_ = tle.inclination_;
    right_ascending_node_ = tle.right_ascending_node_;
    eccentricity_ = tle.eccentricity_;
    argument_perigee_ = tle.argument_perigee_;
    mean_anomaly_ = tle.mean_anomaly_;
    mean_motion_ = tle.mean_motion_;
    orbit_number_ = tle.orbit_number_;
}

Tle::~Tle() {
}

/*
 * convert a tle raw string into an exponent string
 */
std::string Tle::ExpToDecimal(const std::string& str) {

    static const int START_SIGN = 0;
    static const int LENGTH_SIGN = 1;
    static const int START_MANTISSA = 1;
    static const int LENGTH_MANTISSA = 5;
    static const int START_EXP = 6;
    static const int LENGTH_EXP = 2;

    assert(8 == str.length());

    std::string value = str.substr(START_SIGN, LENGTH_SIGN);
    value += ".";
    value += str.substr(START_MANTISSA, LENGTH_MANTISSA);
    value += "e";
    value += str.substr(START_EXP, LENGTH_EXP);

    return value;
}

/*
 * extract all variables
 */
void Tle::Initialize() {

    std::string temp;

    /*
     * trim whitespace
     */
    TrimLeft(name_);
    TrimRight(name_);
    TrimLeft(line_one_);
    TrimRight(line_one_);
    TrimLeft(line_two_);
    TrimRight(line_two_);

    /*
     * check the two lines are valid
     */
    assert(IsValidPair(line_one_, line_two_));

    /*
     * line 1
     */

    temp = line_one_.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM).c_str();
    norad_number_ = atoi(temp.c_str());
    /*
     * if blank use norad number
     */
    if (name_.empty())
        name_ = temp;

    international_designator_ = line_one_.substr(TLE1_COL_INTLDESC_A, TLE1_LEN_INTLDESC_A + TLE1_LEN_INTLDESC_B + TLE1_LEN_INTLDESC_C);

    int year = atoi(line_one_.substr(TLE1_COL_EPOCH_A, TLE1_LEN_EPOCH_A).c_str());
    double day = atof(line_one_.substr(TLE1_COL_EPOCH_B, TLE1_LEN_EPOCH_B).c_str());
    /*
     * generate julian date for epoch
     */
    if (year < 57)
        year += 2000;
    else
        year += 1900;

    epoch_ = Julian(year, day);

    if (line_one_[TLE1_COL_MEANMOTIONDT] == '-') {
        temp = "-0";
    } else
        temp = "0";
    temp += line_one_.substr(TLE1_COL_MEANMOTIONDT + 1, TLE1_LEN_MEANMOTIONDT);
    mean_motion_dot_ = atof(temp.c_str());

    temp = ExpToDecimal(line_one_.substr(TLE1_COL_MEANMOTIONDT2, TLE1_LEN_MEANMOTIONDT2));
    mean_motion_dot2_ = atof(temp.c_str());

    temp = ExpToDecimal(line_one_.substr(TLE1_COL_BSTAR, TLE1_LEN_BSTAR).c_str());
    bstar_ = atof(temp.c_str());

    /*
     * line 2
     */

    temp = line_two_.substr(TLE2_COL_INCLINATION, TLE2_LEN_INCLINATION);
    TrimLeft(temp);
    inclination_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_RAASCENDNODE, TLE2_LEN_RAASCENDNODE);
    TrimLeft(temp);
    right_ascending_node_ = atof(temp.c_str());

    temp = "0.";
    temp += line_two_.substr(TLE2_COL_ECCENTRICITY, TLE2_LEN_ECCENTRICITY);
    eccentricity_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_ARGPERIGEE, TLE2_LEN_ARGPERIGEE);
    TrimLeft(temp);
    argument_perigee_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_MEANANOMALY, TLE2_LEN_MEANANOMALY);
    TrimLeft(temp);
    mean_anomaly_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_MEANMOTION, TLE2_LEN_MEANMOTION);
    TrimLeft(temp);
    mean_motion_ = atof(temp.c_str());

    temp = line_two_.substr(TLE2_COL_REVATEPOCH, TLE2_LEN_REVATEPOCH);
    TrimLeft(temp);
    orbit_number_ = atoi(temp.c_str());
}

/*
 * check the two lines have matching norad numbers
 * and that the lines themselves are valid
 */
bool Tle::IsValidPair(const std::string& line1, const std::string& line2) {

    if (!IsValidLine(line1, 1))
        return false;

    if (!IsValidLine(line2, 2))
        return false;

    if (atoi(line1.substr(TLE1_COL_NORADNUM, TLE1_LEN_NORADNUM).c_str()) !=
            atoi(line2.substr(TLE2_COL_NORADNUM, TLE2_LEN_NORADNUM).c_str()))
        return false;

    return true;
}

/*
 * validate a line
 */
bool Tle::IsValidLine(const std::string& str, const unsigned char line_number) {

    static const std::string line1_pattern = "1 NNNNNC XXXXXXXX NNNNN.NNNNNNNN +.NNNNNNNN +NNNNN-N +NNNNN-N N NNNNN";
    static const std::string line2_pattern = "2 NNNNN NNN.NNNN NNN.NNNN NNNNNNN NNN.NNNN NNN.NNNN NN.NNNNNNNNNNNNNN";

    /*
     * validate line against the pattern
     */
    if (1 == line_number) {
        if (!ValidateLine(str, line1_pattern))
            return false;
    } else if (2 == line_number) {
        if (!ValidateLine(str, line2_pattern))
            return false;
    }

    /*
     * last char in string is modulo 10 checksum
     * edited out as checksum isnt consistent
     *
     * int chk = CheckSum(str);
     * if (chk != (str[TLE_LEN_LINE_DATA - 1] - '0'))
     *   return false;
     */

    return true;
}

/*
 * validate line given a pattern
 */
bool Tle::ValidateLine(const std::string& line, const std::string& pattern) {

    /*
     * check length of lines match
     */
    if (line.length() < pattern.length()) {
        return false;
    }

    std::string::const_iterator pattern_itr = pattern.begin();
    std::string::const_iterator line_itr = line.begin();

    while (pattern_itr != pattern.end()) {

        if (isdigit(*pattern_itr) || *pattern_itr == ' ' ||
                *pattern_itr == '.') {

            /*
             * these characters should match exactly
             */
            if (*pattern_itr != *line_itr)
                return false;

        } else if (*pattern_itr == 'N') {

            /*
             * if pattern value is 'N' then either a number or a ' '
             */
            if (!isdigit(*line_itr) && *line_itr != ' ')
                return false;

        } else if (*pattern_itr == '+') {

            /*
             * if pattern value is '+' then either a '+' or '-' or ' ' or '0'
             */
            if (*line_itr != '+' && *line_itr != '-' && *line_itr != ' ' && *line_itr != '0')
                return false;

        } else if (*pattern_itr == '-') {

            /*
             * if pattern value is '+' or '-'
             */
            if (*line_itr != '+' && *line_itr != '-')
                return false;
        }

        pattern_itr++;
        line_itr++;
    }

    return true;
}

/*
 * compute checksum
 */
int Tle::CheckSum(const std::string& str) {

    size_t len = str.size() - 1;
    int xsum = 0;

    for (size_t i = 0; i < len; i++) {

        char ch = str[i];

        if (isdigit(ch))
            xsum += (ch - '0');
        else
            if (ch == '-')
            xsum++;
    }

    return (xsum % 10);
}

/*
 * trim left of string
 */
void Tle::TrimLeft(std::string& str) {

    std::string whitespaces(" \t\f\n\r");

    if (!str.empty()) {
        std::string::size_type pos = str.find_first_not_of(whitespaces);

        if (pos != std::string::npos)
            str.erase(0, pos);
        else
            str.clear();
    }
}

/*
 * trim right of string
 */
void Tle::TrimRight(std::string& str) {

    std::string whitespaces(" \t\f\n\r");

    if (!str.empty()) {
        std::string::size_type pos = str.find_last_not_of(whitespaces);

        if (pos != std::string::npos)
            str.erase(pos + 1);
        else
            str.clear();
    }
}

<|endoftext|>