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

#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>
#include "ProtocolGraph.h"
#include "RewriteContext.h"
#include "RewriteSystem.h"

using namespace swift;
using namespace rewriting;

/// If this is a rule of the form T.[p] => T where [p] is a property symbol,
/// returns the symbol. Otherwise, returns None.
///
/// Note that this is meant to be used with a simplified rewrite system,
/// where the right hand sides of rules are canonical, since this also means
/// that T is canonical.
Optional<Symbol> Rule::isPropertyRule() const {
  auto property = LHS.back();

  if (!property.isProperty())
    return None;

  if (LHS.size() - 1 != RHS.size())
    return None;

  if (!std::equal(RHS.begin(), RHS.end(), LHS.begin()))
    return None;

  // A same-type requirement of the form 'Self.Foo == Self' can induce a
  // conformance rule [P].[P] => [P]. Don't consider this a property-like
  // rule, since it messes up the generating conformances algorithm and
  // doesn't mean anything useful anyway.
  if (RHS.size() == 1 && RHS[0] == LHS[1])
    return None;

  return property;
}

/// If this is a rule of the form T.[p] => T where [p] is a protocol symbol,
/// return true, otherwise return false.
bool Rule::isProtocolConformanceRule() const {
  if (auto property = isPropertyRule())
    return property->getKind() == Symbol::Kind::Protocol;

  return false;
}

void Rule::dump(llvm::raw_ostream &out) const {
  out << LHS << " => " << RHS;
  if (Permanent)
    out << " [permanent]";
  if (Simplified)
    out << " [simplified]";
  if (Redundant)
    out << " [redundant]";
}

RewriteSystem::RewriteSystem(RewriteContext &ctx)
    : Context(ctx), Debug(ctx.getDebugOptions()) {}

RewriteSystem::~RewriteSystem() {
  Trie.updateHistograms(Context.RuleTrieHistogram,
                        Context.RuleTrieRootHistogram);
}

void RewriteSystem::initialize(
    std::vector<std::pair<MutableTerm, MutableTerm>> &&associatedTypeRules,
    std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
    ProtocolGraph &&graph) {
  Protos = graph;

  for (const auto &rule : associatedTypeRules) {
    bool added = addRule(rule.first, rule.second);
    if (added)
      Rules.back().markPermanent();
  }

  for (const auto &rule : requirementRules)
    addRule(rule.first, rule.second);
}

/// Adds a rewrite rule, returning true if the new rule was non-trivial.
///
/// If both sides simplify to the same term, the rule is trivial and discarded,
/// and this method returns false.
///
/// If \p path is non-null, the new rule is derived from existing rules in the
/// rewrite system; the path records a series of rewrite steps which transform
/// \p lhs to \p rhs.
bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
                            const RewritePath *path) {
  assert(!lhs.empty());
  assert(!rhs.empty());

  if (Debug.contains(DebugFlags::Add)) {
    llvm::dbgs() << "# Adding rule " << lhs << " == " << rhs << "\n\n";
  }

  // Now simplify both sides as much as possible with the rules we have so far.
  //
  // This avoids unnecessary work in the completion algorithm.
  RewritePath lhsPath;
  RewritePath rhsPath;

  simplify(lhs, &lhsPath);
  simplify(rhs, &rhsPath);

  RewritePath loop;
  if (path) {
    // Produce a path from the simplified lhs to the simplified rhs.

    // (1) First, apply lhsPath in reverse to produce the original lhs.
    lhsPath.invert();
    loop.append(lhsPath);

    // (2) Now, apply the path from the original lhs to the original rhs
    // given to us by the completion procedure.
    loop.append(*path);

    // (3) Finally, apply rhsPath to produce the simplified rhs, which
    // is the same as the simplified lhs.
    loop.append(rhsPath);
  }

  // If the left hand side and right hand side are already equivalent, we're
  // done.
  int result = lhs.compare(rhs, Protos);
  if (result == 0) {
    // If this rule is a consequence of existing rules, add a homotopy
    // generator.
    if (path) {
      // We already have a loop, since the simplified lhs is identical to the
      // simplified rhs.
      HomotopyGenerators.emplace_back(lhs, loop);

      if (Debug.contains(DebugFlags::Add)) {
        llvm::dbgs() << "## Recorded trivial loop at " << lhs << ": ";
        loop.dump(llvm::dbgs(), lhs, *this);
        llvm::dbgs() << "\n\n";
      }
    }

    return false;
  }

  // Orient the two terms so that the left hand side is greater than the
  // right hand side.
  if (result < 0) {
    std::swap(lhs, rhs);
    loop.invert();
  }

  assert(lhs.compare(rhs, Protos) > 0);

  if (Debug.contains(DebugFlags::Add)) {
    llvm::dbgs() << "## Simplified and oriented rule " << lhs << " => " << rhs << "\n\n";
  }

  unsigned newRuleID = Rules.size();

  auto uniquedLHS = Term::get(lhs, Context);
  auto uniquedRHS = Term::get(rhs, Context);
  Rules.emplace_back(uniquedLHS, uniquedRHS);

  if (path) {
    // We have a rewrite path from the simplified lhs to the simplified rhs;
    // add a rewrite step applying the new rule in reverse to close the loop.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         newRuleID, /*inverse=*/true));
    HomotopyGenerators.emplace_back(lhs, loop);

    if (Debug.contains(DebugFlags::Add)) {
      llvm::dbgs() << "## Recorded non-trivial loop at " << lhs << ": ";
      loop.dump(llvm::dbgs(), lhs, *this);
      llvm::dbgs() << "\n\n";
    }
  }

  auto oldRuleID = Trie.insert(lhs.begin(), lhs.end(), newRuleID);
  if (oldRuleID) {
    llvm::errs() << "Duplicate rewrite rule!\n";
    const auto &oldRule = getRule(*oldRuleID);
    llvm::errs() << "Old rule #" << *oldRuleID << ": ";
    oldRule.dump(llvm::errs());
    llvm::errs() << "\nTrying to replay what happened when I simplified this term:\n";
    Debug |= DebugFlags::Simplify;
    MutableTerm term = lhs;
    simplify(lhs);

    abort();
  }

  checkMergedAssociatedType(uniquedLHS, uniquedRHS);

  // Tell the caller that we added a new rule.
  return true;
}

/// Reduce a term by applying all rewrite rules until fixed point.
///
/// If \p path is non-null, records the series of rewrite steps taken.
bool RewriteSystem::simplify(MutableTerm &term, RewritePath *path) const {
  bool changed = false;

  MutableTerm original;
  RewritePath forDebug;
  if (Debug.contains(DebugFlags::Simplify)) {

    original = term;
    if (!path)
      path = &forDebug;
  }

  while (true) {
    bool tryAgain = false;

    auto from = term.begin();
    auto end = term.end();
    while (from < end) {
      auto ruleID = Trie.find(from, end);
      if (ruleID) {
        const auto &rule = getRule(*ruleID);
        if (!rule.isSimplified()) {
          auto to = from + rule.getLHS().size();
          assert(std::equal(from, to, rule.getLHS().begin()));

          unsigned startOffset = (unsigned)(from - term.begin());
          unsigned endOffset = term.size() - rule.getLHS().size() - startOffset;

          term.rewriteSubTerm(from, to, rule.getRHS());

          if (path) {
            path->add(RewriteStep::forRewriteRule(startOffset, endOffset, *ruleID,
                                                  /*inverse=*/false));
          }

          changed = true;
          tryAgain = true;
          break;
        }
      }

      ++from;
    }

    if (!tryAgain)
      break;
  }

  if (Debug.contains(DebugFlags::Simplify)) {
    if (changed) {
      llvm::dbgs() << "= Simplified " << term << ": ";
      forDebug.dump(llvm::dbgs(), original, *this);
      llvm::dbgs() << "\n";
    } else {
      llvm::dbgs() << "= Irreducible term: " << term << "\n";
    }
  }

  assert(path == nullptr || changed != path->empty());
  return changed;
}

/// Delete any rules whose left hand sides can be reduced by other rules,
/// and reduce the right hand sides of all remaining rules as much as
/// possible.
///
/// Must be run after the completion procedure, since the deletion of
/// rules is only valid to perform if the rewrite system is confluent.
void RewriteSystem::simplifyRewriteSystem() {
  for (unsigned ruleID = 0, e = Rules.size(); ruleID < e; ++ruleID) {
    auto &rule = getRule(ruleID);
    if (rule.isSimplified())
      continue;

    // First, see if the left hand side of this rule can be reduced using
    // some other rule.
    auto lhs = rule.getLHS();
    auto begin = lhs.begin();
    auto end = lhs.end();
    while (begin < end) {
      if (auto otherRuleID = Trie.find(begin++, end)) {
        // A rule does not obsolete itself.
        if (*otherRuleID == ruleID)
          continue;

        // Ignore other deleted rules.
        if (getRule(*otherRuleID).isSimplified())
          continue;

        if (Debug.contains(DebugFlags::Completion)) {
          const auto &otherRule = getRule(ruleID);
          llvm::dbgs() << "$ Deleting rule " << rule << " because "
                       << "its left hand side contains " << otherRule
                       << "\n";
        }

        rule.markSimplified();
        break;
      }
    }

    // If the rule was deleted above, skip the rest.
    if (rule.isSimplified())
      continue;

    // Now, try to reduce the right hand side.
    RewritePath rhsPath;
    MutableTerm rhs(rule.getRHS());
    if (!simplify(rhs, &rhsPath))
      continue;

    // We're adding a new rule, so the old rule won't apply anymore.
    rule.markSimplified();

    unsigned newRuleID = Rules.size();

    // Add a new rule with the simplified right hand side.
    Rules.emplace_back(lhs, Term::get(rhs, Context));
    auto oldRuleID = Trie.insert(lhs.begin(), lhs.end(), newRuleID);
    assert(oldRuleID == ruleID);
    (void) oldRuleID;

    // Produce a loop at the simplified rhs.
    RewritePath loop;

    // (1) First, apply rhsPath in reverse to produce the original rhs.
    rhsPath.invert();
    loop.append(rhsPath);

    // (2) Next, apply the original rule in reverse to produce the
    // original lhs.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         ruleID, /*inverse=*/true));

    // (3) Finally, apply the new rule to produce the simplified rhs.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         newRuleID, /*inverse=*/false));

    if (Debug.contains(DebugFlags::Completion)) {
      llvm::dbgs() << "$ Right hand side simplification recorded a loop: ";
      loop.dump(llvm::dbgs(), rhs, *this);
    }

    HomotopyGenerators.emplace_back(rhs, loop);
  }
}

void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const {
#ifndef NDEBUG

#define ASSERT_RULE(expr) \
  if (!(expr)) { \
    llvm::errs() << "&&& Malformed rewrite rule: " << rule << "\n"; \
    llvm::errs() << "&&& " << #expr << "\n\n"; \
    dump(llvm::errs()); \
    assert(expr); \
  }

  for (const auto &rule : Rules) {
    if (rule.isSimplified())
      continue;

    const auto &lhs = rule.getLHS();
    const auto &rhs = rule.getRHS();

    for (unsigned index : indices(lhs)) {
      auto symbol = lhs[index];

      if (index != lhs.size() - 1) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Layout);
        ASSERT_RULE(!symbol.isSuperclassOrConcreteType());
      }

      if (index != 0) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::GenericParam);
      }

      if (index != 0 && index != lhs.size() - 1) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Protocol);
      }
    }

    for (unsigned index : indices(rhs)) {
      auto symbol = rhs[index];

      // This is only true if the input requirements were valid.
      if (policy == DisallowInvalidRequirements) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Name);
      } else {
        // FIXME: Assert that we diagnosed an error
      }

      ASSERT_RULE(symbol.getKind() != Symbol::Kind::Layout);
      ASSERT_RULE(!symbol.isSuperclassOrConcreteType());

      if (index != 0) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::GenericParam);
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Protocol);
      }
    }

    auto lhsDomain = lhs.getRootProtocols();
    auto rhsDomain = rhs.getRootProtocols();

    ASSERT_RULE(lhsDomain == rhsDomain);
  }

#undef ASSERT_RULE
#endif
}

void RewriteSystem::dump(llvm::raw_ostream &out) const {
  out << "Rewrite system: {\n";
  for (const auto &rule : Rules) {
    out << "- " << rule << "\n";
  }
  out << "}\n";
  out << "Homotopy generators: {\n";
  for (const auto &loop : HomotopyGenerators) {
    out << "- ";
    loop.dump(out, *this);
    out << "\n";
  }
  out << "}\n";
}
<commit_msg>RequirementMachine: Fix -debug-requirement-machine=simplify output<commit_after>//===--- RewriteSystem.cpp - Generics with term rewriting -----------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "swift/AST/Decl.h"
#include "swift/AST/Types.h"
#include "llvm/ADT/FoldingSet.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <vector>
#include "ProtocolGraph.h"
#include "RewriteContext.h"
#include "RewriteSystem.h"

using namespace swift;
using namespace rewriting;

/// If this is a rule of the form T.[p] => T where [p] is a property symbol,
/// returns the symbol. Otherwise, returns None.
///
/// Note that this is meant to be used with a simplified rewrite system,
/// where the right hand sides of rules are canonical, since this also means
/// that T is canonical.
Optional<Symbol> Rule::isPropertyRule() const {
  auto property = LHS.back();

  if (!property.isProperty())
    return None;

  if (LHS.size() - 1 != RHS.size())
    return None;

  if (!std::equal(RHS.begin(), RHS.end(), LHS.begin()))
    return None;

  // A same-type requirement of the form 'Self.Foo == Self' can induce a
  // conformance rule [P].[P] => [P]. Don't consider this a property-like
  // rule, since it messes up the generating conformances algorithm and
  // doesn't mean anything useful anyway.
  if (RHS.size() == 1 && RHS[0] == LHS[1])
    return None;

  return property;
}

/// If this is a rule of the form T.[p] => T where [p] is a protocol symbol,
/// return true, otherwise return false.
bool Rule::isProtocolConformanceRule() const {
  if (auto property = isPropertyRule())
    return property->getKind() == Symbol::Kind::Protocol;

  return false;
}

void Rule::dump(llvm::raw_ostream &out) const {
  out << LHS << " => " << RHS;
  if (Permanent)
    out << " [permanent]";
  if (Simplified)
    out << " [simplified]";
  if (Redundant)
    out << " [redundant]";
}

RewriteSystem::RewriteSystem(RewriteContext &ctx)
    : Context(ctx), Debug(ctx.getDebugOptions()) {}

RewriteSystem::~RewriteSystem() {
  Trie.updateHistograms(Context.RuleTrieHistogram,
                        Context.RuleTrieRootHistogram);
}

void RewriteSystem::initialize(
    std::vector<std::pair<MutableTerm, MutableTerm>> &&associatedTypeRules,
    std::vector<std::pair<MutableTerm, MutableTerm>> &&requirementRules,
    ProtocolGraph &&graph) {
  Protos = graph;

  for (const auto &rule : associatedTypeRules) {
    bool added = addRule(rule.first, rule.second);
    if (added)
      Rules.back().markPermanent();
  }

  for (const auto &rule : requirementRules)
    addRule(rule.first, rule.second);
}

/// Adds a rewrite rule, returning true if the new rule was non-trivial.
///
/// If both sides simplify to the same term, the rule is trivial and discarded,
/// and this method returns false.
///
/// If \p path is non-null, the new rule is derived from existing rules in the
/// rewrite system; the path records a series of rewrite steps which transform
/// \p lhs to \p rhs.
bool RewriteSystem::addRule(MutableTerm lhs, MutableTerm rhs,
                            const RewritePath *path) {
  assert(!lhs.empty());
  assert(!rhs.empty());

  if (Debug.contains(DebugFlags::Add)) {
    llvm::dbgs() << "# Adding rule " << lhs << " == " << rhs << "\n\n";
  }

  // Now simplify both sides as much as possible with the rules we have so far.
  //
  // This avoids unnecessary work in the completion algorithm.
  RewritePath lhsPath;
  RewritePath rhsPath;

  simplify(lhs, &lhsPath);
  simplify(rhs, &rhsPath);

  RewritePath loop;
  if (path) {
    // Produce a path from the simplified lhs to the simplified rhs.

    // (1) First, apply lhsPath in reverse to produce the original lhs.
    lhsPath.invert();
    loop.append(lhsPath);

    // (2) Now, apply the path from the original lhs to the original rhs
    // given to us by the completion procedure.
    loop.append(*path);

    // (3) Finally, apply rhsPath to produce the simplified rhs, which
    // is the same as the simplified lhs.
    loop.append(rhsPath);
  }

  // If the left hand side and right hand side are already equivalent, we're
  // done.
  int result = lhs.compare(rhs, Protos);
  if (result == 0) {
    // If this rule is a consequence of existing rules, add a homotopy
    // generator.
    if (path) {
      // We already have a loop, since the simplified lhs is identical to the
      // simplified rhs.
      HomotopyGenerators.emplace_back(lhs, loop);

      if (Debug.contains(DebugFlags::Add)) {
        llvm::dbgs() << "## Recorded trivial loop at " << lhs << ": ";
        loop.dump(llvm::dbgs(), lhs, *this);
        llvm::dbgs() << "\n\n";
      }
    }

    return false;
  }

  // Orient the two terms so that the left hand side is greater than the
  // right hand side.
  if (result < 0) {
    std::swap(lhs, rhs);
    loop.invert();
  }

  assert(lhs.compare(rhs, Protos) > 0);

  if (Debug.contains(DebugFlags::Add)) {
    llvm::dbgs() << "## Simplified and oriented rule " << lhs << " => " << rhs << "\n\n";
  }

  unsigned newRuleID = Rules.size();

  auto uniquedLHS = Term::get(lhs, Context);
  auto uniquedRHS = Term::get(rhs, Context);
  Rules.emplace_back(uniquedLHS, uniquedRHS);

  if (path) {
    // We have a rewrite path from the simplified lhs to the simplified rhs;
    // add a rewrite step applying the new rule in reverse to close the loop.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         newRuleID, /*inverse=*/true));
    HomotopyGenerators.emplace_back(lhs, loop);

    if (Debug.contains(DebugFlags::Add)) {
      llvm::dbgs() << "## Recorded non-trivial loop at " << lhs << ": ";
      loop.dump(llvm::dbgs(), lhs, *this);
      llvm::dbgs() << "\n\n";
    }
  }

  auto oldRuleID = Trie.insert(lhs.begin(), lhs.end(), newRuleID);
  if (oldRuleID) {
    llvm::errs() << "Duplicate rewrite rule!\n";
    const auto &oldRule = getRule(*oldRuleID);
    llvm::errs() << "Old rule #" << *oldRuleID << ": ";
    oldRule.dump(llvm::errs());
    llvm::errs() << "\nTrying to replay what happened when I simplified this term:\n";
    Debug |= DebugFlags::Simplify;
    MutableTerm term = lhs;
    simplify(lhs);

    abort();
  }

  checkMergedAssociatedType(uniquedLHS, uniquedRHS);

  // Tell the caller that we added a new rule.
  return true;
}

/// Reduce a term by applying all rewrite rules until fixed point.
///
/// If \p path is non-null, records the series of rewrite steps taken.
bool RewriteSystem::simplify(MutableTerm &term, RewritePath *path) const {
  bool changed = false;

  MutableTerm original;
  RewritePath forDebug;
  if (Debug.contains(DebugFlags::Simplify)) {

    original = term;
    if (!path)
      path = &forDebug;
  }

  while (true) {
    bool tryAgain = false;

    auto from = term.begin();
    auto end = term.end();
    while (from < end) {
      auto ruleID = Trie.find(from, end);
      if (ruleID) {
        const auto &rule = getRule(*ruleID);
        if (!rule.isSimplified()) {
          auto to = from + rule.getLHS().size();
          assert(std::equal(from, to, rule.getLHS().begin()));

          unsigned startOffset = (unsigned)(from - term.begin());
          unsigned endOffset = term.size() - rule.getLHS().size() - startOffset;

          term.rewriteSubTerm(from, to, rule.getRHS());

          if (path) {
            path->add(RewriteStep::forRewriteRule(startOffset, endOffset, *ruleID,
                                                  /*inverse=*/false));
          }

          changed = true;
          tryAgain = true;
          break;
        }
      }

      ++from;
    }

    if (!tryAgain)
      break;
  }

  if (Debug.contains(DebugFlags::Simplify)) {
    if (changed) {
      llvm::dbgs() << "= Simplified " << original << " to " << term << " via ";
      (path == nullptr ? &forDebug : path)->dump(llvm::dbgs(), original, *this);
      llvm::dbgs() << "\n";
    } else {
      llvm::dbgs() << "= Irreducible term: " << term << "\n";
    }
  }

  assert(path == nullptr || changed != path->empty());
  return changed;
}

/// Delete any rules whose left hand sides can be reduced by other rules,
/// and reduce the right hand sides of all remaining rules as much as
/// possible.
///
/// Must be run after the completion procedure, since the deletion of
/// rules is only valid to perform if the rewrite system is confluent.
void RewriteSystem::simplifyRewriteSystem() {
  for (unsigned ruleID = 0, e = Rules.size(); ruleID < e; ++ruleID) {
    auto &rule = getRule(ruleID);
    if (rule.isSimplified())
      continue;

    // First, see if the left hand side of this rule can be reduced using
    // some other rule.
    auto lhs = rule.getLHS();
    auto begin = lhs.begin();
    auto end = lhs.end();
    while (begin < end) {
      if (auto otherRuleID = Trie.find(begin++, end)) {
        // A rule does not obsolete itself.
        if (*otherRuleID == ruleID)
          continue;

        // Ignore other deleted rules.
        if (getRule(*otherRuleID).isSimplified())
          continue;

        if (Debug.contains(DebugFlags::Completion)) {
          const auto &otherRule = getRule(ruleID);
          llvm::dbgs() << "$ Deleting rule " << rule << " because "
                       << "its left hand side contains " << otherRule
                       << "\n";
        }

        rule.markSimplified();
        break;
      }
    }

    // If the rule was deleted above, skip the rest.
    if (rule.isSimplified())
      continue;

    // Now, try to reduce the right hand side.
    RewritePath rhsPath;
    MutableTerm rhs(rule.getRHS());
    if (!simplify(rhs, &rhsPath))
      continue;

    // We're adding a new rule, so the old rule won't apply anymore.
    rule.markSimplified();

    unsigned newRuleID = Rules.size();

    // Add a new rule with the simplified right hand side.
    Rules.emplace_back(lhs, Term::get(rhs, Context));
    auto oldRuleID = Trie.insert(lhs.begin(), lhs.end(), newRuleID);
    assert(oldRuleID == ruleID);
    (void) oldRuleID;

    // Produce a loop at the simplified rhs.
    RewritePath loop;

    // (1) First, apply rhsPath in reverse to produce the original rhs.
    rhsPath.invert();
    loop.append(rhsPath);

    // (2) Next, apply the original rule in reverse to produce the
    // original lhs.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         ruleID, /*inverse=*/true));

    // (3) Finally, apply the new rule to produce the simplified rhs.
    loop.add(RewriteStep::forRewriteRule(/*startOffset=*/0, /*endOffset=*/0,
                                         newRuleID, /*inverse=*/false));

    if (Debug.contains(DebugFlags::Completion)) {
      llvm::dbgs() << "$ Right hand side simplification recorded a loop: ";
      loop.dump(llvm::dbgs(), rhs, *this);
    }

    HomotopyGenerators.emplace_back(rhs, loop);
  }
}

void RewriteSystem::verifyRewriteRules(ValidityPolicy policy) const {
#ifndef NDEBUG

#define ASSERT_RULE(expr) \
  if (!(expr)) { \
    llvm::errs() << "&&& Malformed rewrite rule: " << rule << "\n"; \
    llvm::errs() << "&&& " << #expr << "\n\n"; \
    dump(llvm::errs()); \
    assert(expr); \
  }

  for (const auto &rule : Rules) {
    if (rule.isSimplified())
      continue;

    const auto &lhs = rule.getLHS();
    const auto &rhs = rule.getRHS();

    for (unsigned index : indices(lhs)) {
      auto symbol = lhs[index];

      if (index != lhs.size() - 1) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Layout);
        ASSERT_RULE(!symbol.isSuperclassOrConcreteType());
      }

      if (index != 0) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::GenericParam);
      }

      if (index != 0 && index != lhs.size() - 1) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Protocol);
      }
    }

    for (unsigned index : indices(rhs)) {
      auto symbol = rhs[index];

      // This is only true if the input requirements were valid.
      if (policy == DisallowInvalidRequirements) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Name);
      } else {
        // FIXME: Assert that we diagnosed an error
      }

      ASSERT_RULE(symbol.getKind() != Symbol::Kind::Layout);
      ASSERT_RULE(!symbol.isSuperclassOrConcreteType());

      if (index != 0) {
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::GenericParam);
        ASSERT_RULE(symbol.getKind() != Symbol::Kind::Protocol);
      }
    }

    auto lhsDomain = lhs.getRootProtocols();
    auto rhsDomain = rhs.getRootProtocols();

    ASSERT_RULE(lhsDomain == rhsDomain);
  }

#undef ASSERT_RULE
#endif
}

void RewriteSystem::dump(llvm::raw_ostream &out) const {
  out << "Rewrite system: {\n";
  for (const auto &rule : Rules) {
    out << "- " << rule << "\n";
  }
  out << "}\n";
  out << "Homotopy generators: {\n";
  for (const auto &loop : HomotopyGenerators) {
    out << "- ";
    loop.dump(out, *this);
    out << "\n";
  }
  out << "}\n";
}
<|endoftext|>


<commit_before>/***********************************************************************
    filename:   CEGUIExceptions.cpp
    created:    20/2/2004
    author:     Paul D Turner, Frederico Jeronimo (fjeronimo)

    purpose:    Implements the exception classes used within the system
*************************************************************************/
/***************************************************************************
*   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
*
*   Permission is hereby granted, free of charge, to any person obtaining
*   a copy of this software and associated documentation files (the
*   "Software"), to deal in the Software without restriction, including
*   without limitation the rights to use, copy, modify, merge, publish,
*   distribute, sublicense, and/or sell copies of the Software, and to
*   permit persons to whom the Software is furnished to do so, subject to
*   the following conditions:
*
*   The above copyright notice and this permission notice shall be
*   included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "CEGUIExceptions.h"
#include "CEGUILogger.h"
#include "CEGUIPropertyHelper.h"
#include <iostream>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
Exception::Exception(const String& message, const String& name,
                     const String& filename, int line) :
    d_message(message),
    d_filename(filename),
    d_name(name),
    d_line(line),
    d_what(name + " in file " + filename  +
           "(" + PropertyHelper::intToString(line) + ") : " + message)
{
    // Log exception or send it to error stream (if logger not available)
    Logger* const logger = Logger::getSingletonPtr();
    if (logger)
        logger->logEvent(d_what, Errors);
    else
        std::cerr << what() << std::endl;
}

//----------------------------------------------------------------------------//
Exception::~Exception(void) throw()
{
}

//----------------------------------------------------------------------------//
const char* Exception::what() const throw()
{
    return d_what.c_str();
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<commit_msg>MOD: Always output exception messages to stderr.<commit_after>/***********************************************************************
    filename:   CEGUIExceptions.cpp
    created:    20/2/2004
    author:     Paul D Turner, Frederico Jeronimo (fjeronimo)

    purpose:    Implements the exception classes used within the system
*************************************************************************/
/***************************************************************************
*   Copyright (C) 2004 - 2009 Paul D Turner & The CEGUI Development Team
*
*   Permission is hereby granted, free of charge, to any person obtaining
*   a copy of this software and associated documentation files (the
*   "Software"), to deal in the Software without restriction, including
*   without limitation the rights to use, copy, modify, merge, publish,
*   distribute, sublicense, and/or sell copies of the Software, and to
*   permit persons to whom the Software is furnished to do so, subject to
*   the following conditions:
*
*   The above copyright notice and this permission notice shall be
*   included in all copies or substantial portions of the Software.
*
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
*   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
*   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
*   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
*   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
*   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
*   OTHER DEALINGS IN THE SOFTWARE.
***************************************************************************/
#include "CEGUIExceptions.h"
#include "CEGUILogger.h"
#include "CEGUIPropertyHelper.h"
#include <iostream>

// Start of CEGUI namespace section
namespace CEGUI
{
//----------------------------------------------------------------------------//
Exception::Exception(const String& message, const String& name,
                     const String& filename, int line) :
    d_message(message),
    d_filename(filename),
    d_name(name),
    d_line(line),
    d_what(name + " in file " + filename  +
           "(" + PropertyHelper::intToString(line) + ") : " + message)
{
    // Log exception if possible
    Logger* const logger = Logger::getSingletonPtr();
    if (logger)
        logger->logEvent(d_what, Errors);

    // always output to stderr, since nobody seems to look in their log file!
    std::cerr << what() << std::endl;
}

//----------------------------------------------------------------------------//
Exception::~Exception(void) throw()
{
}

//----------------------------------------------------------------------------//
const char* Exception::what() const throw()
{
    return d_what.c_str();
}

//----------------------------------------------------------------------------//

} // End of  CEGUI namespace section
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright (C) 2012  Alec Moskvin <alecm@gmx.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <LXQt/Notification>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->pushButton, SIGNAL(clicked()), SLOT(createNotification()));
    LXQt::Notification::notify("1");
    LXQt::Notification::notify("2");
    LXQt::Notification::notify("3");
}

void MainWindow::createNotification()
{
    LXQt::Notification* n = new LXQt::Notification("Notification!");
    nlist.append(n);
    connect(n, SIGNAL(actionActivated(int)), this, SLOT(clickEvent(int)));
    n->setActions(QStringList() << "Hi" << "Bye" << "foo" << "bar" << "lorem" << "ipsum", 1);
    n->setIcon("preferences-desktop-launch-feedback");
    n->update();
}

void MainWindow::clickEvent(int button)
{
    LXQt::Notification* n = qobject_cast<LXQt::Notification*>(sender());
    if (n)
    {
        if (button == 0)
        {
            n->setBody("Hello!");
        }
        else
        {
            n->setBody("Closing...");
            n->setTimeout(1000);
        }
        n->update();
    }
}

MainWindow::~MainWindow()
{
    delete ui;
    qDeleteAll(nlist);
}
<commit_msg>Don't use automatic string conversions<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXQt - a lightweight, Qt based, desktop toolset
 * https://lxqt.org
 *
 * Copyright (C) 2012  Alec Moskvin <alecm@gmx.com>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <LXQt/Notification>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->pushButton, SIGNAL(clicked()), SLOT(createNotification()));
    LXQt::Notification::notify(QStringLiteral("1"));
    LXQt::Notification::notify(QStringLiteral("2"));
    LXQt::Notification::notify(QStringLiteral("3"));
}

void MainWindow::createNotification()
{
    LXQt::Notification* n = new LXQt::Notification(QStringLiteral("Notification!"));
    nlist.append(n);
    connect(n, SIGNAL(actionActivated(int)), this, SLOT(clickEvent(int)));
    n->setActions(QStringList()
            << QStringLiteral("Hi")
            << QStringLiteral("Bye")
            << QStringLiteral("foo")
            << QStringLiteral("bar")
            << QStringLiteral("lorem")
            << QStringLiteral("ipsum"),
    1);
    n->setIcon(QStringLiteral("preferences-desktop-launch-feedback"));
    n->update();
}

void MainWindow::clickEvent(int button)
{
    LXQt::Notification* n = qobject_cast<LXQt::Notification*>(sender());
    if (n)
    {
        if (button == 0)
        {
            n->setBody(QStringLiteral("Hello!"));
        }
        else
        {
            n->setBody(QStringLiteral("Closing..."));
            n->setTimeout(1000);
        }
        n->update();
    }
}

MainWindow::~MainWindow()
{
    delete ui;
    qDeleteAll(nlist);
}
<|endoftext|>


<commit_before>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  All rights reserved.                                                              */
/*                                                                                */
/*  Redistribution and use in source and binary forms, with or without modification,  */
/*  are permitted provided that the following conditions are met:                     */
/*                                                                                */
/*  - Redistributions of source code must retain the above copyright notice, this     */
/*  list of conditions and the following disclaimer.                                  */
/*                                                                                */
/*  - Redistributions in binary form must reproduce the above copyright notice, this  */
/*  list of conditions and the following disclaimer in the documentation and/or       */
/*  other materials provided with the distribution.                                   */
/*                                                                                */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
/*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
/*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
/*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
/*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
/*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
/*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
/*                                                                                */
/**************************************************************************************/

#include <vl/Billboard.hpp>
#include <vl/Camera.hpp>

using namespace vl;

//-----------------------------------------------------------------------------
Billboard::Billboard()
{
  setAxis(vec3(0,1,0));
  setNormal(vec3(0,0,1));
  mType = BT_SphericalBillboard;
  #ifndef NDEBUG
    mObjectName = className();
  #endif
}
//-----------------------------------------------------------------------------
vec3 Billboard::position()
{
  return localMatrix().getT();
}
//-----------------------------------------------------------------------------
void Billboard::setPosition(const vec3& pos)
{
  setLocalMatrix( mat4::translation(pos) );
}
//-----------------------------------------------------------------------------
void Billboard::computeWorldMatrix(Camera* camera)
{
  if( alwaysIdentityWorldMatrix() )
  {
    setWorldMatrix( mat4() );
  }
  else
  if ( !camera )
  {
    Transform::computeWorldMatrix(NULL);
  }
  else
  {
    mat4 world_mat;
    vec3 pos = position();
    if (parent() && !parent()->alwaysIdentityWorldMatrix())
      pos = parent()->worldMatrix() * pos;
    if ( type() == BT_SphericalBillboard )
    {
      // eye positional
      world_mat.setZ( (camera->inverseViewMatrix().getT() - pos).normalize() );
      world_mat.setY( camera->inverseViewMatrix().getY() );
      world_mat.setX( cross(world_mat.getY(), world_mat.getZ()) );
      world_mat = vl::mat4::translation(pos) * world_mat;

      // eye directional
      //world_mat.setZ( camera->inverseViewMatrix().getZ() );
      //world_mat.setY( camera->inverseViewMatrix().getY() );
      //world_mat.setX( camera->inverseViewMatrix().getX() );
      //world_mat = vl::mat4::translation(pos) * world_mat;
    }
    else
    if ( type() == BT_AxisAlignedBillboard )
    {
      vec3 normal = mNormal;
      vec3 bill_to_eye = (camera->inverseViewMatrix().getT() - pos).normalize();
      // flatten on the plane defined by the axis()
      normal      = normal      - axis() * dot(normal,      axis());
      bill_to_eye = bill_to_eye - axis() * dot(bill_to_eye, axis());
      normal.normalize();
      bill_to_eye.normalize();
      world_mat = vl::mat4::translation(pos) * mat4::rotation(normal,bill_to_eye);
    }

    setWorldMatrix( world_mat );
  }
}
//-----------------------------------------------------------------------------
<commit_msg>API! alwaysIdentityWorldMatrix() renamed  assumeIdentityWorldMatrix()<commit_after>/**************************************************************************************/
/*                                                                                */
/*  Visualization Library                                                             */
/*  http://www.visualizationlibrary.com                                               */
/*                                                                                */
/*  Copyright (c) 2005-2010, Michele Bosi                                             */
/*  All rights reserved.                                                              */
/*                                                                                */
/*  Redistribution and use in source and binary forms, with or without modification,  */
/*  are permitted provided that the following conditions are met:                     */
/*                                                                                */
/*  - Redistributions of source code must retain the above copyright notice, this     */
/*  list of conditions and the following disclaimer.                                  */
/*                                                                                */
/*  - Redistributions in binary form must reproduce the above copyright notice, this  */
/*  list of conditions and the following disclaimer in the documentation and/or       */
/*  other materials provided with the distribution.                                   */
/*                                                                                */
/*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND   */
/*  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED     */
/*  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE            */
/*  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR  */
/*  ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES    */
/*  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;      */
/*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON    */
/*  ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT           */
/*  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS     */
/*  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                      */
/*                                                                                */
/**************************************************************************************/

#include <vl/Billboard.hpp>
#include <vl/Camera.hpp>

using namespace vl;

//-----------------------------------------------------------------------------
Billboard::Billboard()
{
  setAxis(vec3(0,1,0));
  setNormal(vec3(0,0,1));
  mType = BT_SphericalBillboard;
  #ifndef NDEBUG
    mObjectName = className();
  #endif
}
//-----------------------------------------------------------------------------
vec3 Billboard::position()
{
  return localMatrix().getT();
}
//-----------------------------------------------------------------------------
void Billboard::setPosition(const vec3& pos)
{
  setLocalMatrix( mat4::translation(pos) );
}
//-----------------------------------------------------------------------------
void Billboard::computeWorldMatrix(Camera* camera)
{
  if( assumeIdentityWorldMatrix() )
  {
    setWorldMatrix( mat4() );
  }
  else
  if ( !camera )
  {
    Transform::computeWorldMatrix(NULL);
  }
  else
  {
    mat4 world_mat;
    vec3 pos = position();
    if (parent() && !parent()->assumeIdentityWorldMatrix())
      pos = parent()->worldMatrix() * pos;
    if ( type() == BT_SphericalBillboard )
    {
      // eye positional
      world_mat.setZ( (camera->inverseViewMatrix().getT() - pos).normalize() );
      world_mat.setY( camera->inverseViewMatrix().getY() );
      world_mat.setX( cross(world_mat.getY(), world_mat.getZ()) );
      world_mat = vl::mat4::translation(pos) * world_mat;

      // eye directional
      //world_mat.setZ( camera->inverseViewMatrix().getZ() );
      //world_mat.setY( camera->inverseViewMatrix().getY() );
      //world_mat.setX( camera->inverseViewMatrix().getX() );
      //world_mat = vl::mat4::translation(pos) * world_mat;
    }
    else
    if ( type() == BT_AxisAlignedBillboard )
    {
      vec3 normal = mNormal;
      vec3 bill_to_eye = (camera->inverseViewMatrix().getT() - pos).normalize();
      // flatten on the plane defined by the axis()
      normal      = normal      - axis() * dot(normal,      axis());
      bill_to_eye = bill_to_eye - axis() * dot(bill_to_eye, axis());
      normal.normalize();
      bill_to_eye.normalize();
      world_mat = vl::mat4::translation(pos) * mat4::rotation(normal,bill_to_eye);
    }

    setWorldMatrix( world_mat );
  }
}
//-----------------------------------------------------------------------------
<|endoftext|>


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

  Library:   CTK

  Copyright (c) Kitware Inc.

  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.txt

  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.

=========================================================================*/

// Qt includes
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QKeyEvent>
#include <QTimer>
#include <QString>

// ctk includes
#include "ctkUtils.h"

// ctkDICOMCore includes
#include "ctkDICOMAppWidget.h"

// STD includes
#include <iostream>

/* Test from build directory:
 ./CTK-build/bin/CTKDICOMWidgetsCppTests ctkDICOMAppWidgetTest1 <test directory>

 if the test directory does not have 100 instances in one patient/study/series, test will fail
*/

int ctkDICOMAppWidgetTest1( int argc, char * argv [] )
{
  QApplication app(argc, argv);

  ctkDICOMAppWidget appWidget;

  QFileInfo tempFileInfo(QDir::tempPath() + QString("/ctkDICOMAppWidgetTest1-db"));
  QString dbDir = tempFileInfo.absoluteFilePath();
  std::cerr << "\n\nUsing directory: " << dbDir.toLatin1().data() << std::endl;
  if (tempFileInfo.exists())
    {
    std::cerr << "\n\nRemoving directory: " << dbDir.toLatin1().data() << std::endl;
    ctk::removeDirRecursively(dbDir);
    }
  std::cerr << "\n\nMaking directory: " << dbDir.toLatin1().data() << std::endl;
  QDir dir(dbDir);
  dir.mkdir(dbDir);

  appWidget.setDatabaseDirectory(dbDir);
  QString testString = QString("Test String");
  appWidget.onFileIndexed(testString);
  appWidget.openImportDialog();
  appWidget.openExportDialog();
  appWidget.openQueryDialog();

  appWidget.openQueryDialog();

  appWidget.setDisplayImportSummary(false);
  appWidget.onImportDirectory(argv[argc -1]);
  if ( appWidget.patientsAddedDuringImport() != 1
    || appWidget.studiesAddedDuringImport() != 1
    || appWidget.seriesAddedDuringImport() != 1
    || appWidget.instancesAddedDuringImport() != 100)
    {
    std::cerr << "\n\nDirectory did not import as expected!\n\n";
    exit(-1);
    }

  if (argc <= 2 || QString(argv[1]) != "-I")
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }
  std::cerr << "\n\nAdded to database directory: " << dbDir.toLatin1().data() << std::endl;
  return app.exec();
}
<commit_msg>Some style changes<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Kitware Inc.

  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.txt

  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.

=========================================================================*/

// Qt includes
#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QTimer>
#include <QString>

// ctk includes
#include "ctkUtils.h"

// ctkDICOMCore includes
#include "ctkDICOMAppWidget.h"

// STD includes
#include <iostream>

/* Test from build directory:
 ./CTK-build/bin/CTKDICOMWidgetsCppTests ctkDICOMAppWidgetTest1 <test directory>

 if the test directory does not have 100 instances in one patient/study/series, test will fail
*/

int ctkDICOMAppWidgetTest1( int argc, char * argv [] )
{
  QApplication app(argc, argv);

  ctkDICOMAppWidget appWidget;

  QFileInfo tempFileInfo(QDir::tempPath() + QString("/ctkDICOMAppWidgetTest1-db"));
  QString dbDir = tempFileInfo.absoluteFilePath();
  qDebug() << "\n\nUsing directory: " << dbDir;
  if (tempFileInfo.exists())
    {
    qDebug() << "\n\nRemoving directory: " << dbDir;
    ctk::removeDirRecursively(dbDir);
    }
  qDebug() << "\n\nMaking directory: " << dbDir;
  QDir dir(dbDir);
  dir.mkdir(dbDir);

  appWidget.setDatabaseDirectory(dbDir);
  QString testString = QString("Test String");
  appWidget.onFileIndexed(testString);
  appWidget.openImportDialog();
  appWidget.openExportDialog();
  appWidget.openQueryDialog();

  appWidget.openQueryDialog();

  appWidget.setDisplayImportSummary(false);
  appWidget.onImportDirectory(argv[argc -1]);
  if ( appWidget.patientsAddedDuringImport() != 1
    || appWidget.studiesAddedDuringImport() != 1
    || appWidget.seriesAddedDuringImport() != 1
    || appWidget.instancesAddedDuringImport() != 100)
    {
    qDebug() << "\n\nDirectory did not import as expected!\n\n";
    return EXIT_FAILURE;
    }

  if (argc <= 2 || QString(argv[1]) != "-I")
    {
    QTimer::singleShot(200, &app, SLOT(quit()));
    }
  qDebug() << "\n\nAdded to database directory: " << dbDir;
  return app.exec();
}
<|endoftext|>


<commit_before>/* -*- Mode: C++ -*-
   $Id$
   KDGantt - a multi-platform charting engine
*/
/****************************************************************************
 ** Copyright (C)  2002-2004 Klarlvdalens Datakonsult AB.  All rights reserved.
 **
 ** This file is part of the KDGantt library.
 **
 ** This file may be distributed and/or modified under the terms of the
 ** GNU General Public License version 2 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.
 **
 ** Licensees holding valid commercial KDGantt licenses may use this file in
 ** accordance with the KDGantt Commercial License Agreement provided with
 ** the Software.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for
 **   information about KDGantt Commercial License Agreements.
 **
 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
 ** licensing are not clear to you.
 **
 ** As a special exception, permission is given to link this program
 ** with any edition of Qt, and distribute the resulting executable,
 ** without including the source code for Qt in the source distribution.
 **
 **********************************************************************/

#include "KDGanttViewTaskLinkGroup.h"
#include "KDGanttXMLTools.h"
#include "KDGanttView.h"

QDict<KDGanttViewTaskLinkGroup> KDGanttViewTaskLinkGroup::sGroupDict;

/*! \class KDGanttViewTaskLinkGroup KDGanttViewTaskLinkGroup.h
  A group of task links.

  This class groups a number of task links together in order to
  manipulate them uniformly.
*/

/*!
  Constructs an empty task link group
*/
KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup()
{
    generateAndInsertName(QString());
}

/*!
  Destructor
  Removes this task link group from the list of task link groups in the
  KDGanttView class.
*/
KDGanttViewTaskLinkGroup::~KDGanttViewTaskLinkGroup()
{
    if (!myTaskLinkList.isEmpty()) {
        myTaskLinkList.first()->from().first()->myGanttView->removeTaskLinkGroup(this);
    }
}

/*!
  Constructs an empty task link group and records it under the name \a
  name so that it can later be found again with
  KDGanttViewTaskLinkGroup::find().

  \param name the search name of this task link group
*/
KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup( const QString& name )
{
    generateAndInsertName( name );
}

/*!
  Adds a task link LINK to this group. If the task link is already a member of
  another group, it will be removed from it.
  This function is equivalent to  LINK->setGroup(this), where this is
  a pointer to this TaskLinkGroup.
  \param link a pointer to the task link to add to this task link group
  visible, and false to hide them
  \sa remove()
*/
void KDGanttViewTaskLinkGroup::insert (KDGanttViewTaskLink* link)
{
    link->setGroup(this);
}

/*!
  Removes a task link LINK from this group.
  You may remove a tasklink  LINK from its group with  LINK->setGroup(0).

  \param link a pointer to the task link to remove from this task link group
  \return true if the task link was a member of this group
  \sa insert()
*/
bool KDGanttViewTaskLinkGroup::remove (KDGanttViewTaskLink* link)
{
    KDGanttViewTaskLinkGroup* g = link->group();
    if ((g == this))
        link->setGroup(0);
    return (g == this);
}

/*!
  Specifies whether the task links of this group should be visible or not.

  \param show visible pass true to make the task links of this group
  visible, and false to hide them
  \sa isVisible()
*/
void KDGanttViewTaskLinkGroup::setVisible( bool show )
{
    isvisible = show;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it ) {
        it.current()->setVisible(show);
    }
}

/*!
  Returns whether the task links of this group should be visible or not.

  \return true if the task links of this group are visible
  \sa setVisible()
*/
bool KDGanttViewTaskLinkGroup::visible() const
{
    return isvisible;
}

/*!
  Specifies whether the task links of this group should be shown
  highlighted. The user can also highlight a task link with the mouse.

  \param highlight pass true in order to highlight the task links in
  this group
  \sa highlight()
*/
void KDGanttViewTaskLinkGroup::setHighlight( bool highlight )
{
    ishighlighted=  highlight;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setHighlight(highlight );

}

/*!
  Returns whether all task links in this group are highlighted, either
  programmatically by setHighlight() or by the user with the
  mouse. This method is not particularly useful and is mainly provided
  for API uniformity reasons.

  \return true if all the task links in this group are highlighted
  \sa setHighlight()
*/
bool KDGanttViewTaskLinkGroup::highlight() const
{
    return ishighlighted;
}

/*!
  Specifies the color to draw the task links in this group in.

  \param color the color to draw the task links in this group in
  \sa color()
*/
void KDGanttViewTaskLinkGroup::setColor( const QColor& color )
{
    myColor = color;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setColor(color);
}

/*!
  Returns the color in which the task links in this group are
  drawn. If task links have been assigned individual colors, the
  return value of this method is undefined. This method is not
  particularly useful and is mainly provided for API uniformity
  reasons.

  \return the color in which the task links in this group are drawn
  \sa setColor()
*/
QColor KDGanttViewTaskLinkGroup::color() const
{
    return myColor;
}

/*!
  Specifies the highlight color to draw the task links in this group in.

  \param color the highlight color to draw the task links in this group in
  \sa color()
*/
void KDGanttViewTaskLinkGroup::setHighlightColor( const QColor& color )
{

    myColorHL = color;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setHighlightColor(color);
}

/*!
  Returns the highlight color in which the task links in this group are
  drawn. If task links have been assigned individual highlight colors,
  the return value of this method is undefined. This method is not
  particularly useful and is mainly provided for API uniformity reasons.

  \return the highlight color in which the task links in this group
  are drawn
  \sa setColor()
*/
QColor KDGanttViewTaskLinkGroup::highlightColor() const
{
    return myColorHL;
}

/*!
  Adds a task link LINK to this group. If the task link is already a member of
  another group, it will  not be removed from it.
  \param a pointer to the task link to add to this task link group
  visible, and false to hide them
  \sa removeItem()
*/
void KDGanttViewTaskLinkGroup::insertItem (KDGanttViewTaskLink* link)
{
    myTaskLinkList.append (link);
}

/*!
  Removes a task link LINK from this group.

  \param a pointer to the task link to remove from this task link group
  \sa insertItem()
*/
void KDGanttViewTaskLinkGroup::removeItem (KDGanttViewTaskLink* link)
{
    myTaskLinkList.remove(link);
}

/*!
  Returns the task link group with the specified name.

  \param name the name to search for
  \return the task link group with the specified name; 0 if no group
  with that name exists
*/
KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::find( const QString& name )
{
    if (name.isEmpty()) // avoid error msg from QDict
        return 0;
    return sGroupDict.find( name );
}

/*!
  Creates a DOM node that describes this task link group.

  \param doc the DOM document to which the node belongs
  \param parentElement the element into which to insert this node
*/
void KDGanttViewTaskLinkGroup::createNode( QDomDocument& doc,
                                           QDomElement& parentElement )
{
    QDomElement taskLinkGroupElement = doc.createElement( "TaskLink" );
    parentElement.appendChild( taskLinkGroupElement );

    KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Highlight",
                           highlight() );
    KDGanttXML::createColorNode( doc, taskLinkGroupElement, "Color", color() );
    KDGanttXML::createColorNode( doc, taskLinkGroupElement, "HighlightColor",
                            highlightColor() );
    KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Visible",
                           visible() );
    KDGanttXML::createStringNode( doc, taskLinkGroupElement, "Name", _name );
}

/*!
  Creates a KDGanttViewTaskLinkGroup according to the specification in a DOM
  element.

  \param element the DOM element from which to read the specification
  \return the newly created task link group
*/
KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::createFromDomElement( QDomElement& element )
{
    QDomNode node = element.firstChild();
    bool highlight = false, visible = false;
    QColor color, highlightColor;
    QString name;
    while( !node.isNull() ) {
        QDomElement element = node.toElement();
        if( !element.isNull() ) { // was really an element
            QString tagName = element.tagName();
            if( tagName == "Highlight" ) {
                bool value;
                if( KDGanttXML::readBoolNode( element, value ) )
                    highlight = value;
            } else if( tagName == "Visible" ) {
                bool value;
                if( KDGanttXML::readBoolNode( element, value ) )
                    visible = value;
            } else if( tagName == "Color" ) {
                QColor value;
                if( KDGanttXML::readColorNode( element, value ) )
                    color = value;
            } else if( tagName == "HighlightColor" ) {
                QColor value;
                if( KDGanttXML::readColorNode( element, value ) )
                    highlightColor = value;
            } else if( tagName == "Name" ) {
                QString value;
                if( KDGanttXML::readStringNode( element, value ) )
                    name = value;
            } else {
                qDebug( "Unrecognized tag name: %s", tagName.latin1() );
                Q_ASSERT( false );
            }
        }
        node = node.nextSibling();
    }

    KDGanttViewTaskLinkGroup* tlg;
    if( !name.isEmpty() )
        tlg = new KDGanttViewTaskLinkGroup( name );
    else
        tlg = new KDGanttViewTaskLinkGroup();

    tlg->setHighlight( highlight );
    tlg->setVisible( visible );
    tlg->setHighlightColor( highlightColor );
    tlg->setColor( color );

    return tlg;
}

/*!
  Generates a unique name if necessary and inserts it into the group
  dictionary.
*/
void KDGanttViewTaskLinkGroup::generateAndInsertName( const QString& name )
{
    // First check if we already had a name. This can be the case if
    // the item was reconstructed from an XML file.
    if( !_name.isEmpty() )
        // We had a name, remove it
        sGroupDict.remove( _name );

    QString newName;
    if ( name.isEmpty() || sGroupDict.find( name ) ) {
        // create unique name
        newName.sprintf( "%p", (void* )this );
        while( sGroupDict.find( newName ) ) {
            newName += "_0";
        }
    } else {
        newName = name;
    }
    sGroupDict.insert( newName, this );
    _name = newName;
    qDebug("KDGanttViewTaskLinkGroup::generateAndInsertName: inserted '%s'",newName.latin1());
}

<commit_msg>Comment out debug statement.<commit_after>/* -*- Mode: C++ -*-
   $Id$
   KDGantt - a multi-platform charting engine
*/
/****************************************************************************
 ** Copyright (C)  2002-2004 Klarlvdalens Datakonsult AB.  All rights reserved.
 **
 ** This file is part of the KDGantt library.
 **
 ** This file may be distributed and/or modified under the terms of the
 ** GNU General Public License version 2 as published by the Free Software
 ** Foundation and appearing in the file LICENSE.GPL included in the
 ** packaging of this file.
 **
 ** Licensees holding valid commercial KDGantt licenses may use this file in
 ** accordance with the KDGantt Commercial License Agreement provided with
 ** the Software.
 **
 ** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 ** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 **
 ** See http://www.klaralvdalens-datakonsult.se/Public/products/ for
 **   information about KDGantt Commercial License Agreements.
 **
 ** Contact info@klaralvdalens-datakonsult.se if any conditions of this
 ** licensing are not clear to you.
 **
 ** As a special exception, permission is given to link this program
 ** with any edition of Qt, and distribute the resulting executable,
 ** without including the source code for Qt in the source distribution.
 **
 **********************************************************************/

#include "KDGanttViewTaskLinkGroup.h"
#include "KDGanttXMLTools.h"
#include "KDGanttView.h"

QDict<KDGanttViewTaskLinkGroup> KDGanttViewTaskLinkGroup::sGroupDict;

/*! \class KDGanttViewTaskLinkGroup KDGanttViewTaskLinkGroup.h
  A group of task links.

  This class groups a number of task links together in order to
  manipulate them uniformly.
*/

/*!
  Constructs an empty task link group
*/
KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup()
{
    generateAndInsertName(QString());
}

/*!
  Destructor
  Removes this task link group from the list of task link groups in the
  KDGanttView class.
*/
KDGanttViewTaskLinkGroup::~KDGanttViewTaskLinkGroup()
{
    if (!myTaskLinkList.isEmpty()) {
        myTaskLinkList.first()->from().first()->myGanttView->removeTaskLinkGroup(this);
    }
}

/*!
  Constructs an empty task link group and records it under the name \a
  name so that it can later be found again with
  KDGanttViewTaskLinkGroup::find().

  \param name the search name of this task link group
*/
KDGanttViewTaskLinkGroup::KDGanttViewTaskLinkGroup( const QString& name )
{
    generateAndInsertName( name );
}

/*!
  Adds a task link LINK to this group. If the task link is already a member of
  another group, it will be removed from it.
  This function is equivalent to  LINK->setGroup(this), where this is
  a pointer to this TaskLinkGroup.
  \param link a pointer to the task link to add to this task link group
  visible, and false to hide them
  \sa remove()
*/
void KDGanttViewTaskLinkGroup::insert (KDGanttViewTaskLink* link)
{
    link->setGroup(this);
}

/*!
  Removes a task link LINK from this group.
  You may remove a tasklink  LINK from its group with  LINK->setGroup(0).

  \param link a pointer to the task link to remove from this task link group
  \return true if the task link was a member of this group
  \sa insert()
*/
bool KDGanttViewTaskLinkGroup::remove (KDGanttViewTaskLink* link)
{
    KDGanttViewTaskLinkGroup* g = link->group();
    if ((g == this))
        link->setGroup(0);
    return (g == this);
}

/*!
  Specifies whether the task links of this group should be visible or not.

  \param show visible pass true to make the task links of this group
  visible, and false to hide them
  \sa isVisible()
*/
void KDGanttViewTaskLinkGroup::setVisible( bool show )
{
    isvisible = show;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it ) {
        it.current()->setVisible(show);
    }
}

/*!
  Returns whether the task links of this group should be visible or not.

  \return true if the task links of this group are visible
  \sa setVisible()
*/
bool KDGanttViewTaskLinkGroup::visible() const
{
    return isvisible;
}

/*!
  Specifies whether the task links of this group should be shown
  highlighted. The user can also highlight a task link with the mouse.

  \param highlight pass true in order to highlight the task links in
  this group
  \sa highlight()
*/
void KDGanttViewTaskLinkGroup::setHighlight( bool highlight )
{
    ishighlighted=  highlight;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setHighlight(highlight );

}

/*!
  Returns whether all task links in this group are highlighted, either
  programmatically by setHighlight() or by the user with the
  mouse. This method is not particularly useful and is mainly provided
  for API uniformity reasons.

  \return true if all the task links in this group are highlighted
  \sa setHighlight()
*/
bool KDGanttViewTaskLinkGroup::highlight() const
{
    return ishighlighted;
}

/*!
  Specifies the color to draw the task links in this group in.

  \param color the color to draw the task links in this group in
  \sa color()
*/
void KDGanttViewTaskLinkGroup::setColor( const QColor& color )
{
    myColor = color;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setColor(color);
}

/*!
  Returns the color in which the task links in this group are
  drawn. If task links have been assigned individual colors, the
  return value of this method is undefined. This method is not
  particularly useful and is mainly provided for API uniformity
  reasons.

  \return the color in which the task links in this group are drawn
  \sa setColor()
*/
QColor KDGanttViewTaskLinkGroup::color() const
{
    return myColor;
}

/*!
  Specifies the highlight color to draw the task links in this group in.

  \param color the highlight color to draw the task links in this group in
  \sa color()
*/
void KDGanttViewTaskLinkGroup::setHighlightColor( const QColor& color )
{

    myColorHL = color;
    QPtrListIterator<KDGanttViewTaskLink> it(myTaskLinkList);
    for ( ; it.current(); ++it )
        it.current()->setHighlightColor(color);
}

/*!
  Returns the highlight color in which the task links in this group are
  drawn. If task links have been assigned individual highlight colors,
  the return value of this method is undefined. This method is not
  particularly useful and is mainly provided for API uniformity reasons.

  \return the highlight color in which the task links in this group
  are drawn
  \sa setColor()
*/
QColor KDGanttViewTaskLinkGroup::highlightColor() const
{
    return myColorHL;
}

/*!
  Adds a task link LINK to this group. If the task link is already a member of
  another group, it will  not be removed from it.
  \param a pointer to the task link to add to this task link group
  visible, and false to hide them
  \sa removeItem()
*/
void KDGanttViewTaskLinkGroup::insertItem (KDGanttViewTaskLink* link)
{
    myTaskLinkList.append (link);
}

/*!
  Removes a task link LINK from this group.

  \param a pointer to the task link to remove from this task link group
  \sa insertItem()
*/
void KDGanttViewTaskLinkGroup::removeItem (KDGanttViewTaskLink* link)
{
    myTaskLinkList.remove(link);
}

/*!
  Returns the task link group with the specified name.

  \param name the name to search for
  \return the task link group with the specified name; 0 if no group
  with that name exists
*/
KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::find( const QString& name )
{
    if (name.isEmpty()) // avoid error msg from QDict
        return 0;
    return sGroupDict.find( name );
}

/*!
  Creates a DOM node that describes this task link group.

  \param doc the DOM document to which the node belongs
  \param parentElement the element into which to insert this node
*/
void KDGanttViewTaskLinkGroup::createNode( QDomDocument& doc,
                                           QDomElement& parentElement )
{
    QDomElement taskLinkGroupElement = doc.createElement( "TaskLink" );
    parentElement.appendChild( taskLinkGroupElement );

    KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Highlight",
                           highlight() );
    KDGanttXML::createColorNode( doc, taskLinkGroupElement, "Color", color() );
    KDGanttXML::createColorNode( doc, taskLinkGroupElement, "HighlightColor",
                            highlightColor() );
    KDGanttXML::createBoolNode( doc, taskLinkGroupElement, "Visible",
                           visible() );
    KDGanttXML::createStringNode( doc, taskLinkGroupElement, "Name", _name );
}

/*!
  Creates a KDGanttViewTaskLinkGroup according to the specification in a DOM
  element.

  \param element the DOM element from which to read the specification
  \return the newly created task link group
*/
KDGanttViewTaskLinkGroup* KDGanttViewTaskLinkGroup::createFromDomElement( QDomElement& element )
{
    QDomNode node = element.firstChild();
    bool highlight = false, visible = false;
    QColor color, highlightColor;
    QString name;
    while( !node.isNull() ) {
        QDomElement element = node.toElement();
        if( !element.isNull() ) { // was really an element
            QString tagName = element.tagName();
            if( tagName == "Highlight" ) {
                bool value;
                if( KDGanttXML::readBoolNode( element, value ) )
                    highlight = value;
            } else if( tagName == "Visible" ) {
                bool value;
                if( KDGanttXML::readBoolNode( element, value ) )
                    visible = value;
            } else if( tagName == "Color" ) {
                QColor value;
                if( KDGanttXML::readColorNode( element, value ) )
                    color = value;
            } else if( tagName == "HighlightColor" ) {
                QColor value;
                if( KDGanttXML::readColorNode( element, value ) )
                    highlightColor = value;
            } else if( tagName == "Name" ) {
                QString value;
                if( KDGanttXML::readStringNode( element, value ) )
                    name = value;
            } else {
                qDebug( "Unrecognized tag name: %s", tagName.latin1() );
                Q_ASSERT( false );
            }
        }
        node = node.nextSibling();
    }

    KDGanttViewTaskLinkGroup* tlg;
    if( !name.isEmpty() )
        tlg = new KDGanttViewTaskLinkGroup( name );
    else
        tlg = new KDGanttViewTaskLinkGroup();

    tlg->setHighlight( highlight );
    tlg->setVisible( visible );
    tlg->setHighlightColor( highlightColor );
    tlg->setColor( color );

    return tlg;
}

/*!
  Generates a unique name if necessary and inserts it into the group
  dictionary.
*/
void KDGanttViewTaskLinkGroup::generateAndInsertName( const QString& name )
{
    // First check if we already had a name. This can be the case if
    // the item was reconstructed from an XML file.
    if( !_name.isEmpty() )
        // We had a name, remove it
        sGroupDict.remove( _name );

    QString newName;
    if ( name.isEmpty() || sGroupDict.find( name ) ) {
        // create unique name
        newName.sprintf( "%p", (void* )this );
        while( sGroupDict.find( newName ) ) {
            newName += "_0";
        }
    } else {
        newName = name;
    }
    sGroupDict.insert( newName, this );
    _name = newName;
    //qDebug("KDGanttViewTaskLinkGroup::generateAndInsertName: inserted '%s'",newName.latin1());
}

<|endoftext|>


<commit_before>#include "common.h"
#include "serial_port.h"
#include "system_ids.h"
#include "commander.h"

float north[4] = {-10.0, 0.0, 10.0, 0.0};
float east[4] =  {0.0, 10.0, 0.0, -10.0};

void sendNextCommand() {

	// retrieve the id of the last finished cmd
	int nextCmd = uav.last_cmd_finished_id++;

	// cycle the cmds (ids should go from 0 -> 3)
	if (nextCmd > 3) {
		nextCmd = 0;
	}

	// extract the next north and east commands
	float nextNorth = north[nextCmd];
	float nextEast = east[nextCmd];

	mavlink_tracking_cmd_t tracking_cmd;
	tracking_cmd.timestamp_usec = 0;
	tracking_cmd.north = nextNorth;
	tracking_cmd.east = nextEast;
	tracking_cmd.yaw_angle = 0.0;
	tracking_cmd.altitude = 60.0;
	tracking_cmd.cmd_id = nextCmd;
	tracking_cmd.cmd_type = TRACKING_CMD_TRAVEL;

	mavlink_message_t message;
	mavlink_msg_tracking_cmd_encode(sysid, compid, &message, &tracking_cmd);

	int len = write_to_serial(message);
	printf("Sent buffer of length %i\n",len);

	return;

}

void sendRotateCommand() {
	// retrieve the id of the last finished cmd
	int nextCmd = uav.last_cmd_finished_id++;

	mavlink_tracking_cmd_t tracking_cmd;
	tracking_cmd.timestamp_usec = 0;
	tracking_cmd.north = 0.0;			// don't travel any distance north
	tracking_cmd.east = 0.0;			// don't travel any distacne east
	tracking_cmd.yaw_angle = 1.0;		// rotate clockwise (NOTE: yaw angle no longer means yaw angle, but rather rotation direction)
	tracking_cmd.altitude = 0.0;		// will have pixhawk just use current altitude
	tracking_cmd.cmd_id = nextCmd;
	tracking_cmd.cmd_type = TRACKING_CMD_ROTATE;

	mavlink_message_t message;
	mavlink_msg_tracking_cmd_encode(sysid, compid, &message, &tracking_cmd);

	int len = write_to_serial(message);
	printf("Sent buffer of length %i\n",len);

	return;
}

void send_bearing_message(double &bearing, int32_t &lat, int32_t &lon, float &alt) {

	return;
}

int write_to_serial(mavlink_message_t &message) {

	// buffer needed for mavlink msg send function
	char buf[300];

	// Send message to buffer
	unsigned len = mavlink_msg_to_send_buffer((uint8_t*)buf, &message);

	// Write packet via serial link
	write(fd, buf, len);

	// Wait until all data has been written
	tcdrain(fd);

	return len;

}<commit_msg>adding ability to send bearing mavlink message to pixhawk<commit_after>#include "common.h"
#include "serial_port.h"
#include "system_ids.h"
#include "commander.h"

float north[4] = {-10.0, 0.0, 10.0, 0.0};
float east[4] =  {0.0, 10.0, 0.0, -10.0};

void sendNextCommand() {

	// retrieve the id of the last finished cmd
	int nextCmd = uav.last_cmd_finished_id++;

	// cycle the cmds (ids should go from 0 -> 3)
	if (nextCmd > 3) {
		nextCmd = 0;
	}

	// extract the next north and east commands
	float nextNorth = north[nextCmd];
	float nextEast = east[nextCmd];

	mavlink_tracking_cmd_t tracking_cmd;
	tracking_cmd.timestamp_usec = 0;
	tracking_cmd.north = nextNorth;
	tracking_cmd.east = nextEast;
	tracking_cmd.yaw_angle = 0.0;
	tracking_cmd.altitude = 60.0;
	tracking_cmd.cmd_id = nextCmd;
	tracking_cmd.cmd_type = TRACKING_CMD_TRAVEL;

	mavlink_message_t message;
	mavlink_msg_tracking_cmd_encode(sysid, compid, &message, &tracking_cmd);

	int len = write_to_serial(message);
	printf("Sent buffer of length %i\n",len);

	return;

}

void sendRotateCommand() {
	// retrieve the id of the last finished cmd
	int nextCmd = uav.last_cmd_finished_id++;

	mavlink_tracking_cmd_t tracking_cmd;
	tracking_cmd.timestamp_usec = 0;
	tracking_cmd.north = 0.0;			// don't travel any distance north
	tracking_cmd.east = 0.0;			// don't travel any distacne east
	tracking_cmd.yaw_angle = 1.0;		// rotate clockwise (NOTE: yaw angle no longer means yaw angle, but rather rotation direction)
	tracking_cmd.altitude = 0.0;		// will have pixhawk just use current altitude
	tracking_cmd.cmd_id = nextCmd;
	tracking_cmd.cmd_type = TRACKING_CMD_ROTATE;

	mavlink_message_t message;
	mavlink_msg_tracking_cmd_encode(sysid, compid, &message, &tracking_cmd);

	int len = write_to_serial(message);
	printf("Sent buffer of length %i\n",len);

	return;
}

void send_bearing_message(double &bearing, int32_t &lat, int32_t &lon, float &alt) {

	mavlink_bearing_t bear;
	bear.bearing = bearing;
	bear.lat = lat;
	bear.lon = lon;
	bear.alt = alt;

	mavlink_message_t message;
	mavlink_msg_bearing_encode(sysid, compid, &message, &bear);

	int len = write_to_serial(message);
	printf("Sent buffer of length %i\n",len);

	return;
}

int write_to_serial(mavlink_message_t &message) {

	// buffer needed for mavlink msg send function
	char buf[300];

	// Send message to buffer
	unsigned len = mavlink_msg_to_send_buffer((uint8_t*)buf, &message);

	// Write packet via serial link
	write(fd, buf, len);

	// Wait until all data has been written
	tcdrain(fd);

	return len;

}<|endoftext|>


<commit_before>// This program takes in a trained network and dump all the network
// parameters to a HDF5 file that is readable for Mocha.jl
// Usage:
//    dump_network_hdf5 network_def network_snapshot hdf5_output_filename
//
// Please refer to Mocha's document for details on how to use this tool.

#include <string>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
#include "caffe/vision_layers.hpp"

using namespace std;
using namespace caffe;  // NOLINT(build/namespaces)

void dump_weight_bias(hid_t &h5file, Layer<float> *layer, const string& layer_name, const string& weight_name);

int main(int argc, char** argv) {
  caffe::GlobalInit(&argc, &argv);
  Caffe::set_mode(Caffe::CPU);
  Caffe::set_phase(Caffe::TEST);

  if (argc != 4) {
    LOG(ERROR) << "Usage:";
    LOG(ERROR) << "  " << argv[0] << " net-def.prototxt net-snapshot.caffemodel output.hdf5";
    exit(1);
  }

  const char *network_params   = argv[1];
  const char *network_snapshot = argv[2];
  const char *hdf5_output_fn   = argv[3];

  hid_t file_id = H5Fcreate(hdf5_output_fn, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

  shared_ptr<Net<float> > caffe_net;
  caffe_net.reset(new Net<float>(network_params));
  caffe_net->CopyTrainedLayersFrom(network_snapshot);

  const vector<shared_ptr<Layer<float> > >& layers = caffe_net->layers();
  const vector<string> & layer_names = caffe_net->layer_names();
  for (int i = 0; i < layer_names.size(); ++i) {
    if (InnerProductLayer<float> *layer = dynamic_cast<InnerProductLayer<float> *>(layers[i].get())) {
      LOG(ERROR) << "Dumping InnerProductLayer " << layer_names[i];
      dump_weight_bias(file_id, layer, layer_names[i], string("weight"));
    } else if (ConvolutionLayer<float> *layer = dynamic_cast<ConvolutionLayer<float> *>(layers[i].get())) {
      LOG(ERROR) << "Dumping ConvolutionLayer " << layer_names[i];
      dump_weight_bias(file_id, layer, layer_names[i], string("filter"));
    } else {
      LOG(ERROR) << "Ignoring layer " << layer_names[i];
    }
  }

  H5Fclose(file_id);
  return 0;
}

void dump_weight_bias(hid_t &h5file, Layer<float> *layer, const string& layer_name, const string& weight_name) {
  vector<shared_ptr<Blob<float> > >& blobs = layer->blobs();
  if (blobs.size() == 0) {
    LOG(ERROR) << "Layer " << layer_name << " has no blobs!!!";
    exit(1);
  }

  LOG(ERROR) << "    Exporting weight blob as '" << weight_name << "'";
  hdf5_save_nd_dataset(h5file, layer_name + string("___") + weight_name, *blobs[0]);
  if (blobs.size() > 1) {
    LOG(ERROR) << "    Exporting bias blob as 'bias'";
    hdf5_save_nd_dataset(h5file, layer_name + string("___bias"), *blobs[1]);
  } else if (blobs.size() > 2) {
    LOG(ERROR) << "Layer " << layer_name << " has more than 2 blobs, are you serious? I cannot handle this.";
  } else {
    LOG(ERROR) << "    No bias blob, ignoring";
  }
}
<commit_msg>update Caffe model import script to latest caffe API<commit_after>// This program takes in a trained network and dump all the network
// parameters to a HDF5 file that is readable for Mocha.jl
// Usage:
//    dump_network_hdf5 network_def network_snapshot hdf5_output_filename
//
// Please refer to Mocha's document for details on how to use this tool.

#include <string>
#include <vector>

#include "caffe/blob.hpp"
#include "caffe/net.hpp"
#include "caffe/proto/caffe.pb.h"
#include "caffe/util/io.hpp"
#include "caffe/vision_layers.hpp"

using namespace std;
using namespace caffe;  // NOLINT(build/namespaces)

void dump_weight_bias(hid_t &h5file, Layer<float> *layer, const string& layer_name, const string& weight_name);

int main(int argc, char** argv) {
  caffe::GlobalInit(&argc, &argv);
  Caffe::set_mode(Caffe::CPU);

  if (argc != 4) {
    LOG(ERROR) << "Usage:";
    LOG(ERROR) << "  " << argv[0] << " net-def.prototxt net-snapshot.caffemodel output.hdf5";
    exit(1);
  }

  const char *network_params   = argv[1];
  const char *network_snapshot = argv[2];
  const char *hdf5_output_fn   = argv[3];

  hid_t file_id = H5Fcreate(hdf5_output_fn, H5F_ACC_TRUNC, H5P_DEFAULT, H5P_DEFAULT);

  shared_ptr<Net<float> > caffe_net;
  caffe_net.reset(new Net<float>(network_params, caffe::TEST));
  caffe_net->CopyTrainedLayersFrom(network_snapshot);

  const vector<shared_ptr<Layer<float> > >& layers = caffe_net->layers();
  const vector<string> & layer_names = caffe_net->layer_names();
  for (int i = 0; i < layer_names.size(); ++i) {
    if (InnerProductLayer<float> *layer = dynamic_cast<InnerProductLayer<float> *>(layers[i].get())) {
      LOG(ERROR) << "Dumping InnerProductLayer " << layer_names[i];
      dump_weight_bias(file_id, layer, layer_names[i], string("weight"));
    } else if (ConvolutionLayer<float> *layer = dynamic_cast<ConvolutionLayer<float> *>(layers[i].get())) {
      LOG(ERROR) << "Dumping ConvolutionLayer " << layer_names[i];
      dump_weight_bias(file_id, layer, layer_names[i], string("filter"));
    } else {
      LOG(ERROR) << "Ignoring layer " << layer_names[i];
    }
  }

  H5Fclose(file_id);
  return 0;
}

void dump_weight_bias(hid_t &h5file, Layer<float> *layer, const string& layer_name, const string& weight_name) {
  vector<shared_ptr<Blob<float> > >& blobs = layer->blobs();
  if (blobs.size() == 0) {
    LOG(ERROR) << "Layer " << layer_name << " has no blobs!!!";
    exit(1);
  }

  LOG(ERROR) << "    Exporting weight blob as '" << weight_name << "'";
  hdf5_save_nd_dataset(h5file, layer_name + string("___") + weight_name, *blobs[0]);
  if (blobs.size() > 1) {
    LOG(ERROR) << "    Exporting bias blob as 'bias'";
    hdf5_save_nd_dataset(h5file, layer_name + string("___bias"), *blobs[1]);
  } else if (blobs.size() > 2) {
    LOG(ERROR) << "Layer " << layer_name << " has more than 2 blobs, are you serious? I cannot handle this.";
  } else {
    LOG(ERROR) << "    No bias blob, ignoring";
  }
}
<|endoftext|>