<commit_before>#include "dg/Offset.h"
#include "dg/llvm/LLVMDependenceGraph.h"
#include "dg/llvm/LLVMDependenceGraphBuilder.h"
#include "dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h"
#include "dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h"
#include "dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h"

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Support/CommandLine.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm-slicer.h"
#include "llvm-slicer-utils.h"

#include "git-version.h"

using dg::LLVMPointerAnalysisOptions;
using dg::LLVMDataDependenceAnalysisOptions;

static void
addAllocationFuns(dg::llvmdg::LLVMDependenceGraphOptions& dgOptions,
                  const std::string& allocationFuns) {
    using dg::AllocationFunction;

    auto items = splitList(allocationFuns);
    for (auto& item : items) {
        auto subitms = splitList(item, ':');
        if (subitms.size() != 2) {
            llvm::errs() << "ERROR: Invalid allocation function: " << item << "\n";
            continue;
        }

        AllocationFunction type;
        if (subitms[1] == "malloc")
            type = AllocationFunction::MALLOC;
        else if (subitms[1] == "calloc")
            type = AllocationFunction::CALLOC;
        else if (subitms[1] == "realloc")
            type = AllocationFunction::REALLOC;
        else {
            llvm::errs() << "ERROR: Invalid type of allocation function: "
                         << item << "\n";
            continue;
        }

        dgOptions.PTAOptions.addAllocationFunction(subitms[0], type);
        dgOptions.DDAOptions.addAllocationFunction(subitms[0], type);
    }
}

llvm::cl::OptionCategory SlicingOpts("Slicer options", "");

// Use LLVM's CommandLine library to parse
// command line arguments
SlicerOptions parseSlicerOptions(int argc, char *argv[], bool requireCrit, bool inputFileRequired) {
    llvm::cl::opt<std::string> outputFile("o",
        llvm::cl::desc("Save the output to given file. If not specified,\n"
                       "a .sliced suffix is used with the original module name."),
        llvm::cl::value_desc("filename"), llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> inputFile(llvm::cl::Positional,
        llvm::cl::desc("<input file>"), llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    if (inputFileRequired) {
        inputFile.setNumOccurrencesFlag(llvm::cl::Required);
    }

    llvm::cl::opt<std::string> slicingCriteria("c",
        llvm::cl::desc("Slice with respect to the call-sites of a given function\n"
                       "i. e.: '-c foo' or '-c __assert_fail'. Special value is a 'ret'\n"
                       "in which case the slice is taken with respect to the return value\n"
                       "of the main function. Further, you can specify the criterion as\n"
                       "l:v where l is the line in the original code and v is the variable.\n"
                       "l must be empty when v is a global variable. For local variables,\n"
                       "the variable v must be used on the line l.\n"
                       "You can use comma-separated list of more slicing criteria,\n"
                       "e.g. -c foo,5:x,:glob\n"), llvm::cl::value_desc("crit"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));
    if (requireCrit) {
        slicingCriteria.setNumOccurrencesFlag(llvm::cl::Required);
    }

    llvm::cl::opt<std::string> secondarySlicingCriteria("2c",
        llvm::cl::desc("Set secondary slicing criterion. The criterion is a call\n"
                       "to a given function. If just a name of the function is\n"
                       "given, it is a 'control' slicing criterion. If there is ()\n"
                       "appended, it is 'data' slicing criterion. E.g. foo means\n"
                       "control secondary slicing criterion, foo() means data\n"
                       "data secondary slicing criterion.\n"),
                       llvm::cl::value_desc("crit"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> removeSlicingCriteria("remove-slicing-criteria",
        llvm::cl::desc("By default, slicer keeps also slicing criteria\n"
                       "in the sliced program. This switch makes slicer to remove\n"
                       "also the criteria (i.e. behave like Weisser's algorithm)"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> preservedFuns("preserved-functions",
        llvm::cl::desc("Do not slice bodies of the given functions.\n"
                       "The argument is a comma-separated list of functions.\n"),
                       llvm::cl::value_desc("funs"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> interprocCd("interproc-cd",
        llvm::cl::desc("Compute interprocedural dependencies that cover, e.g.,\n"
                       "calls calls to exit() from inside of procedures. Default: true.\n"),
                       llvm::cl::init(true), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> cdaPerInstr("cda-per-inst",
        llvm::cl::desc("Compute control dependencies per instruction (the default\n"
                       "is per basic block)\n"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<uint64_t> ptaFieldSensitivity("pta-field-sensitive",
        llvm::cl::desc("Make PTA field sensitive/insensitive. The offset in a pointer\n"
                       "is cropped to Offset::UNKNOWN when it is greater than N bytes.\n"
                       "Default is full field-sensitivity (N = Offset::UNKNOWN).\n"),
                       llvm::cl::value_desc("N"), llvm::cl::init(dg::Offset::UNKNOWN),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<dg::dda::UndefinedFunsBehavior> undefinedFunsBehavior("undefined-funs",
        llvm::cl::desc("Set the behavior of undefined functions\n"),
        llvm::cl::values(
            clEnumValN(dg::dda::PURE,       "pure",
                       "Assume that undefined functions do not read nor write memory"),
            clEnumValN(dg::dda::WRITE_ANY,  "write-any",
                       "Assume that undefined functions may write any memory"),
            clEnumValN(dg::dda::READ_ANY,   "read-any",
                       "Assume that undefined functions may read any memory"),
            clEnumValN(dg::dda::READ_ANY | dg::dda::WRITE_ANY,   "rw-any",
                       "Assume that undefined functions may read and write any memory"),
            clEnumValN(dg::dda::WRITE_ARGS, "write-args",
                       "Assume that undefined functions may write to arguments"),
            clEnumValN(dg::dda::READ_ARGS,  "read-args",
                       "Assume that undefined functions may read from arguments (default)"),
            clEnumValN(dg::dda::WRITE_ARGS | dg::dda::READ_ARGS,
                       "rw-args",  "Assume that undefined functions may read or write from/to arguments")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(dg::dda::READ_ARGS), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> entryFunction("entry",
        llvm::cl::desc("Entry function of the program\n"),
                       llvm::cl::init("main"), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> forwardSlicing("forward",
        llvm::cl::desc("Perform forward slicing\n"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> threads("threads",
        llvm::cl::desc("Consider threads are in input file (default=false)."),
        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> allocationFuns("allocation-funs",
        llvm::cl::desc("Treat these functions as allocation functions\n"
                       "The argument is a comma-separated list of func:type,\n"
                       "where func is the function and type is one of\n"
                       "malloc, calloc, or realloc.\n"
                       "E.g., myAlloc:malloc will treat myAlloc as malloc.\n"),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<LLVMPointerAnalysisOptions::AnalysisType> ptaType("pta",
        llvm::cl::desc("Choose pointer analysis to use:"),
        llvm::cl::values(
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fi, "fi", "Flow-insensitive PTA (default)"),
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fs, "fs", "Flow-sensitive PTA"),
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::inv, "inv", "PTA with invalidate nodes")
#ifdef HAVE_SVF
            , clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::svf, "svf", "Use pointer analysis from SVF project")
#endif
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(LLVMPointerAnalysisOptions::AnalysisType::fi), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<LLVMDataDependenceAnalysisOptions::AnalysisType> ddaType("dda",
        llvm::cl::desc("Choose data dependence analysis to use:"),
        llvm::cl::values(
            clEnumValN(LLVMDataDependenceAnalysisOptions::AnalysisType::ssa,
                       "ssa", "MemorySSA DDA (the only option right now)")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(LLVMDataDependenceAnalysisOptions::AnalysisType::ssa),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<dg::ControlDependenceAnalysisOptions::CDAlgorithm> cdAlgorithm("cda",
        llvm::cl::desc("Choose control dependencies algorithm:"),
        llvm::cl::values(
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD,
                       "standard", "Ferrante's algorithm (default)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD,
                       "classic", "Alias to \"standard\""),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD,
                       "ntscd", "Non-termination sensitive control dependencies algorithm"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD2,
                       "ntscd2", "Non-termination sensitive control dependencies algorithm (a different implementation)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_RANGANATH,
                       "ntscd-ranganath",
                       "Non-termination sensitive control dependencies algorithm (the original Ranganath et al.'s algorithm)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_LEGACY,
                       "ntscd-legacy", "Non-termination sensitive control dependencies algorithm (legacy implementation)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DOD_RANGANATH,
                       "dod-ranganath", "Decisive order dependencies algorithm by Ranganath (standalone - for debugging)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DOD,
                       "dod", "Decisive order dependencies algorithm (standalone - for debugging)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DODNTSCD,
                       "dod+ntscd", "NTSCD and DOD together"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STRONG_CC,
                       "scc", "Use strong control closure algorithm")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
             ),
        llvm::cl::init(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD),
        llvm::cl::cat(SlicingOpts));

    llvm::cl::alias cdAlgAlias("cd-alg",
        llvm::cl::desc("Choose control dependencies algorithm to use"
                       "(this options is obsolete, it is alias to -cda):"),
        llvm::cl::aliasopt(cdAlgorithm),
        llvm::cl::cat(SlicingOpts));

    ////////////////////////////////////
    // ===-- End of the options --=== //
    ////////////////////////////////////

    // hide all options except ours options
    // this method is available since LLVM 3.7
#if ((LLVM_VERSION_MAJOR > 3)\
      || ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR >= 7)))
    llvm::cl::HideUnrelatedOptions(SlicingOpts);
#endif
# if ((LLVM_VERSION_MAJOR >= 6))
    llvm::cl::SetVersionPrinter([](llvm::raw_ostream&){ printf("%s\n", GIT_VERSION); });
#else
    llvm::cl::SetVersionPrinter([](){ printf("%s\n", GIT_VERSION); });
#endif
    llvm::cl::ParseCommandLineOptions(argc, argv);

    /// Fill the structure
    SlicerOptions options;

    options.inputFile = inputFile;
    options.outputFile = outputFile;
    options.slicingCriteria = slicingCriteria;
    options.secondarySlicingCriteria = secondarySlicingCriteria;
    options.preservedFunctions = splitList(preservedFuns);
    options.removeSlicingCriteria = removeSlicingCriteria;
    options.forwardSlicing = forwardSlicing;

    auto& dgOptions = options.dgOptions;
    auto& PTAOptions = dgOptions.PTAOptions;
    auto& DDAOptions = dgOptions.DDAOptions;
    auto& CDAOptions = dgOptions.CDAOptions;

    dgOptions.entryFunction = entryFunction;
    dgOptions.threads = threads;

    CDAOptions.algorithm = cdAlgorithm;
    CDAOptions.interprocedural = interprocCd;
    CDAOptions.setNodePerInstruction(cdaPerInstr);

    addAllocationFuns(dgOptions, allocationFuns);

    PTAOptions.entryFunction = entryFunction;
    PTAOptions.fieldSensitivity = dg::Offset(ptaFieldSensitivity);
    PTAOptions.analysisType = ptaType;
    PTAOptions.threads = threads;

    DDAOptions.threads = threads;
    DDAOptions.entryFunction = entryFunction;
    DDAOptions.undefinedFunsBehavior = undefinedFunsBehavior;
    DDAOptions.analysisType = ddaType;

    return options;
}

<commit_msg>CDA opts: add the "scd" alias for "standard"<commit_after>#include "dg/Offset.h"
#include "dg/llvm/LLVMDependenceGraph.h"
#include "dg/llvm/LLVMDependenceGraphBuilder.h"
#include "dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h"
#include "dg/llvm/DataDependence/LLVMDataDependenceAnalysisOptions.h"
#include "dg/llvm/ControlDependence/LLVMControlDependenceAnalysisOptions.h"

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Support/CommandLine.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm-slicer.h"
#include "llvm-slicer-utils.h"

#include "git-version.h"

using dg::LLVMPointerAnalysisOptions;
using dg::LLVMDataDependenceAnalysisOptions;

static void
addAllocationFuns(dg::llvmdg::LLVMDependenceGraphOptions& dgOptions,
                  const std::string& allocationFuns) {
    using dg::AllocationFunction;

    auto items = splitList(allocationFuns);
    for (auto& item : items) {
        auto subitms = splitList(item, ':');
        if (subitms.size() != 2) {
            llvm::errs() << "ERROR: Invalid allocation function: " << item << "\n";
            continue;
        }

        AllocationFunction type;
        if (subitms[1] == "malloc")
            type = AllocationFunction::MALLOC;
        else if (subitms[1] == "calloc")
            type = AllocationFunction::CALLOC;
        else if (subitms[1] == "realloc")
            type = AllocationFunction::REALLOC;
        else {
            llvm::errs() << "ERROR: Invalid type of allocation function: "
                         << item << "\n";
            continue;
        }

        dgOptions.PTAOptions.addAllocationFunction(subitms[0], type);
        dgOptions.DDAOptions.addAllocationFunction(subitms[0], type);
    }
}

llvm::cl::OptionCategory SlicingOpts("Slicer options", "");

// Use LLVM's CommandLine library to parse
// command line arguments
SlicerOptions parseSlicerOptions(int argc, char *argv[], bool requireCrit, bool inputFileRequired) {
    llvm::cl::opt<std::string> outputFile("o",
        llvm::cl::desc("Save the output to given file. If not specified,\n"
                       "a .sliced suffix is used with the original module name."),
        llvm::cl::value_desc("filename"), llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> inputFile(llvm::cl::Positional,
        llvm::cl::desc("<input file>"), llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    if (inputFileRequired) {
        inputFile.setNumOccurrencesFlag(llvm::cl::Required);
    }

    llvm::cl::opt<std::string> slicingCriteria("c",
        llvm::cl::desc("Slice with respect to the call-sites of a given function\n"
                       "i. e.: '-c foo' or '-c __assert_fail'. Special value is a 'ret'\n"
                       "in which case the slice is taken with respect to the return value\n"
                       "of the main function. Further, you can specify the criterion as\n"
                       "l:v where l is the line in the original code and v is the variable.\n"
                       "l must be empty when v is a global variable. For local variables,\n"
                       "the variable v must be used on the line l.\n"
                       "You can use comma-separated list of more slicing criteria,\n"
                       "e.g. -c foo,5:x,:glob\n"), llvm::cl::value_desc("crit"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));
    if (requireCrit) {
        slicingCriteria.setNumOccurrencesFlag(llvm::cl::Required);
    }

    llvm::cl::opt<std::string> secondarySlicingCriteria("2c",
        llvm::cl::desc("Set secondary slicing criterion. The criterion is a call\n"
                       "to a given function. If just a name of the function is\n"
                       "given, it is a 'control' slicing criterion. If there is ()\n"
                       "appended, it is 'data' slicing criterion. E.g. foo means\n"
                       "control secondary slicing criterion, foo() means data\n"
                       "data secondary slicing criterion.\n"),
                       llvm::cl::value_desc("crit"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> removeSlicingCriteria("remove-slicing-criteria",
        llvm::cl::desc("By default, slicer keeps also slicing criteria\n"
                       "in the sliced program. This switch makes slicer to remove\n"
                       "also the criteria (i.e. behave like Weisser's algorithm)"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> preservedFuns("preserved-functions",
        llvm::cl::desc("Do not slice bodies of the given functions.\n"
                       "The argument is a comma-separated list of functions.\n"),
                       llvm::cl::value_desc("funs"),
                       llvm::cl::init(""), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> interprocCd("interproc-cd",
        llvm::cl::desc("Compute interprocedural dependencies that cover, e.g.,\n"
                       "calls calls to exit() from inside of procedures. Default: true.\n"),
                       llvm::cl::init(true), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> cdaPerInstr("cda-per-inst",
        llvm::cl::desc("Compute control dependencies per instruction (the default\n"
                       "is per basic block)\n"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<uint64_t> ptaFieldSensitivity("pta-field-sensitive",
        llvm::cl::desc("Make PTA field sensitive/insensitive. The offset in a pointer\n"
                       "is cropped to Offset::UNKNOWN when it is greater than N bytes.\n"
                       "Default is full field-sensitivity (N = Offset::UNKNOWN).\n"),
                       llvm::cl::value_desc("N"), llvm::cl::init(dg::Offset::UNKNOWN),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<dg::dda::UndefinedFunsBehavior> undefinedFunsBehavior("undefined-funs",
        llvm::cl::desc("Set the behavior of undefined functions\n"),
        llvm::cl::values(
            clEnumValN(dg::dda::PURE,       "pure",
                       "Assume that undefined functions do not read nor write memory"),
            clEnumValN(dg::dda::WRITE_ANY,  "write-any",
                       "Assume that undefined functions may write any memory"),
            clEnumValN(dg::dda::READ_ANY,   "read-any",
                       "Assume that undefined functions may read any memory"),
            clEnumValN(dg::dda::READ_ANY | dg::dda::WRITE_ANY,   "rw-any",
                       "Assume that undefined functions may read and write any memory"),
            clEnumValN(dg::dda::WRITE_ARGS, "write-args",
                       "Assume that undefined functions may write to arguments"),
            clEnumValN(dg::dda::READ_ARGS,  "read-args",
                       "Assume that undefined functions may read from arguments (default)"),
            clEnumValN(dg::dda::WRITE_ARGS | dg::dda::READ_ARGS,
                       "rw-args",  "Assume that undefined functions may read or write from/to arguments")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(dg::dda::READ_ARGS), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> entryFunction("entry",
        llvm::cl::desc("Entry function of the program\n"),
                       llvm::cl::init("main"), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> forwardSlicing("forward",
        llvm::cl::desc("Perform forward slicing\n"),
                       llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<bool> threads("threads",
        llvm::cl::desc("Consider threads are in input file (default=false)."),
        llvm::cl::init(false), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<std::string> allocationFuns("allocation-funs",
        llvm::cl::desc("Treat these functions as allocation functions\n"
                       "The argument is a comma-separated list of func:type,\n"
                       "where func is the function and type is one of\n"
                       "malloc, calloc, or realloc.\n"
                       "E.g., myAlloc:malloc will treat myAlloc as malloc.\n"),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<LLVMPointerAnalysisOptions::AnalysisType> ptaType("pta",
        llvm::cl::desc("Choose pointer analysis to use:"),
        llvm::cl::values(
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fi, "fi", "Flow-insensitive PTA (default)"),
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::fs, "fs", "Flow-sensitive PTA"),
            clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::inv, "inv", "PTA with invalidate nodes")
#ifdef HAVE_SVF
            , clEnumValN(LLVMPointerAnalysisOptions::AnalysisType::svf, "svf", "Use pointer analysis from SVF project")
#endif
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(LLVMPointerAnalysisOptions::AnalysisType::fi), llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<LLVMDataDependenceAnalysisOptions::AnalysisType> ddaType("dda",
        llvm::cl::desc("Choose data dependence analysis to use:"),
        llvm::cl::values(
            clEnumValN(LLVMDataDependenceAnalysisOptions::AnalysisType::ssa,
                       "ssa", "MemorySSA DDA (the only option right now)")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
            ),
        llvm::cl::init(LLVMDataDependenceAnalysisOptions::AnalysisType::ssa),
                       llvm::cl::cat(SlicingOpts));

    llvm::cl::opt<dg::ControlDependenceAnalysisOptions::CDAlgorithm> cdAlgorithm("cda",
        llvm::cl::desc("Choose control dependencies algorithm:"),
        llvm::cl::values(
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD,
                       "standard", "Ferrante's algorithm (default)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD,
                       "classic", "Alias to \"standard\""),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD,
                       "scd", "Alias to \"standard\""),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD,
                       "ntscd", "Non-termination sensitive control dependencies algorithm"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD2,
                       "ntscd2", "Non-termination sensitive control dependencies algorithm (a different implementation)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_RANGANATH,
                       "ntscd-ranganath",
                       "Non-termination sensitive control dependencies algorithm (the original Ranganath et al.'s algorithm)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::NTSCD_LEGACY,
                       "ntscd-legacy", "Non-termination sensitive control dependencies algorithm (legacy implementation)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DOD_RANGANATH,
                       "dod-ranganath", "Decisive order dependencies algorithm by Ranganath et al. - fixed version (standalone - for debugging)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DOD,
                       "dod", "Decisive order dependencies algorithm (standalone - for debugging)"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::DODNTSCD,
                       "dod+ntscd", "NTSCD and DOD together"),
            clEnumValN(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STRONG_CC,
                       "scc", "Use strong control closure algorithm")
    #if LLVM_VERSION_MAJOR < 4
            , nullptr
    #endif
             ),
        llvm::cl::init(dg::ControlDependenceAnalysisOptions::CDAlgorithm::STANDARD),
        llvm::cl::cat(SlicingOpts));

    llvm::cl::alias cdAlgAlias("cd-alg",
        llvm::cl::desc("Choose control dependencies algorithm to use"
                       "(this options is obsolete, it is alias to -cda):"),
        llvm::cl::aliasopt(cdAlgorithm),
        llvm::cl::cat(SlicingOpts));

    ////////////////////////////////////
    // ===-- End of the options --=== //
    ////////////////////////////////////

    // hide all options except ours options
    // this method is available since LLVM 3.7
#if ((LLVM_VERSION_MAJOR > 3)\
      || ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR >= 7)))
    llvm::cl::HideUnrelatedOptions(SlicingOpts);
#endif
# if ((LLVM_VERSION_MAJOR >= 6))
    llvm::cl::SetVersionPrinter([](llvm::raw_ostream&){ printf("%s\n", GIT_VERSION); });
#else
    llvm::cl::SetVersionPrinter([](){ printf("%s\n", GIT_VERSION); });
#endif
    llvm::cl::ParseCommandLineOptions(argc, argv);

    /// Fill the structure
    SlicerOptions options;

    options.inputFile = inputFile;
    options.outputFile = outputFile;
    options.slicingCriteria = slicingCriteria;
    options.secondarySlicingCriteria = secondarySlicingCriteria;
    options.preservedFunctions = splitList(preservedFuns);
    options.removeSlicingCriteria = removeSlicingCriteria;
    options.forwardSlicing = forwardSlicing;

    auto& dgOptions = options.dgOptions;
    auto& PTAOptions = dgOptions.PTAOptions;
    auto& DDAOptions = dgOptions.DDAOptions;
    auto& CDAOptions = dgOptions.CDAOptions;

    dgOptions.entryFunction = entryFunction;
    dgOptions.threads = threads;

    CDAOptions.algorithm = cdAlgorithm;
    CDAOptions.interprocedural = interprocCd;
    CDAOptions.setNodePerInstruction(cdaPerInstr);

    addAllocationFuns(dgOptions, allocationFuns);

    PTAOptions.entryFunction = entryFunction;
    PTAOptions.fieldSensitivity = dg::Offset(ptaFieldSensitivity);
    PTAOptions.analysisType = ptaType;
    PTAOptions.threads = threads;

    DDAOptions.threads = threads;
    DDAOptions.entryFunction = entryFunction;
    DDAOptions.undefinedFunsBehavior = undefinedFunsBehavior;
    DDAOptions.analysisType = ddaType;

    return options;
}

<|endoftext|>


<commit_before>// SciTE - Scintilla based Text Editor
/** @file DirectorExtension.cxx
 ** Extension for communicating with a director program.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "Platform.h"

#include "PropSet.h"

#include "Scintilla.h"
#include "Accessor.h"
#include "Extender.h"
#include "DirectorExtension.h"
#include "SciTE.h"
#include "SciTEBase.h"

static ExtensionAPI *host = 0;
static DirectorExtension *pde = 0;
static HWND wDirector = 0;
static HWND wCorrespondent = 0;
static HWND wReceiver = 0;
static bool startedByDirector = false;
unsigned int SDI = 0;

static void SendDirector(const char *verb, const char *arg = 0) {
	if ((wDirector != 0) || (wCorrespondent != 0)) {
		HWND wDestination = wCorrespondent;
		SString addressedMessage;
		if (wDestination) {
			addressedMessage += ":";
			SString address(reinterpret_cast<int>(wDestination));
			addressedMessage += address;
			addressedMessage += ":";
		} else {
			wDestination = wDirector;
		}
		addressedMessage += verb;
		addressedMessage += ":";
		if (arg)
			addressedMessage += arg;
		char *slashedMessage = Slash(addressedMessage.c_str());
		if (slashedMessage) {
			COPYDATASTRUCT cds;
			cds.dwData = 0;
			cds.cbData = strlen(slashedMessage);
			cds.lpData = reinterpret_cast<void *>(
			                 const_cast<char *>(slashedMessage));
			::SendMessage(wDestination, WM_COPYDATA,
			              reinterpret_cast<WPARAM>(wReceiver),
			              reinterpret_cast<LPARAM>(&cds));
			delete []slashedMessage;
		}
	}
}

static void SendDirector(const char *verb, sptr_t arg) {
	SString s(arg);
	::SendDirector(verb, s.c_str());
}

static void CheckEnvironment(ExtensionAPI *host) {
	if (!host)
		return ;
	if (!wDirector) {
		char *director = host->Property("director.hwnd");
		if (director && *director) {
			startedByDirector = true;
			wDirector = reinterpret_cast<HWND>(atoi(director));
			// Director is just seen so identify this to it
			::SendDirector("identity", reinterpret_cast<sptr_t>(wReceiver));
		}
		delete []director;
	}
	char number[32];
	sprintf(number, "%0d", reinterpret_cast<int>(wReceiver));
	host->SetProperty("WindowID", number);
}

static char DirectorExtension_ClassName[] = "DirectorExtension";

static LRESULT HandleCopyData(LPARAM lParam) {
	COPYDATASTRUCT *pcds = reinterpret_cast<COPYDATASTRUCT *>(lParam);
	// Copy into an temporary buffer to ensure \0 terminated
	if (pde && pcds->lpData) {
		char *dataCopy = new char[pcds->cbData + 1];
		if (dataCopy) {
			strncpy(dataCopy, reinterpret_cast<char *>(pcds->lpData), pcds->cbData);
			dataCopy[pcds->cbData] = '\0';
			pde->HandleStringMessage(dataCopy);
			delete []dataCopy;
		}
	}
	return 0;
}

LRESULT PASCAL DirectorExtension_WndProc(
    HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
	if (iMessage == WM_COPYDATA) {
		return HandleCopyData(lParam);
	} else if (iMessage == SDI) {
		return SDI;
	}
	return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
}

static void DirectorExtension_Register(HINSTANCE hInstance) {
	WNDCLASS wndclass;
	wndclass.style = 0;
	wndclass.lpfnWndProc = DirectorExtension_WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = 0;
	wndclass.hCursor = NULL;
	wndclass.hbrBackground = NULL;
	wndclass.lpszMenuName = 0;
	wndclass.lpszClassName = DirectorExtension_ClassName;
	if (!::RegisterClass(&wndclass))
		::exit(FALSE);
}

DirectorExtension::DirectorExtension() {
	pde = this;
}

DirectorExtension::~DirectorExtension() {
	pde = 0;
}

bool DirectorExtension::Initialise(ExtensionAPI *host_) {
	host = host_;
	SDI = ::RegisterWindowMessage("SciTEDirectorInterface");
	HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(
	                          host->GetInstance());
	DirectorExtension_Register(hInstance);
	wReceiver = ::CreateWindow(
	                DirectorExtension_ClassName,
	                DirectorExtension_ClassName,
	                0,
	                0, 0, 0, 0,
	                0,
	                0,
	                hInstance,
	                0);
	if (!wReceiver)
		::exit(FALSE);
	CheckEnvironment(host);
	return true;
}

bool DirectorExtension::Finalise() {
	::SendDirector("closing");
	if (wReceiver)
		::DestroyWindow(wReceiver);
	wReceiver = 0;
	return true;
}

bool DirectorExtension::Clear() {
	return true;
}

bool DirectorExtension::Load(const char *) {
	return true;
}

bool DirectorExtension::OnOpen(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("opened", path);
	}
	return true;
}

bool DirectorExtension::OnSwitchFile(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("switched", path);
	}
	return true;
};

bool DirectorExtension::OnSave(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("saved", path);
	}
	return true;
}

bool DirectorExtension::OnChar(char) {
	return false;
}

bool DirectorExtension::OnExecute(const char *) {
	return false;
}

bool DirectorExtension::OnSavePointReached() {
	return false;
}

bool DirectorExtension::OnSavePointLeft() {
	return false;
}

bool DirectorExtension::OnStyle(unsigned int, int, int, Accessor *) {
	return false;
}

// These should probably have arguments

bool DirectorExtension::OnDoubleClick() {
	return false;
}

bool DirectorExtension::OnUpdateUI() {
	return false;
}

bool DirectorExtension::OnMarginClick() {
	return false;
}

bool DirectorExtension::OnMacro(const char *command, const char *params) {
	SendDirector(command, params);
	return true;
}

bool DirectorExtension::SendProperty(const char *prop) {
	CheckEnvironment(host);
	if (*prop) {
		::SendDirector("property", prop);
	}
	return true;
}

void DirectorExtension::HandleStringMessage(const char *message) {
	// Message may contain multiple commands separated by '\n'
	// Reentrance trouble - if this function is reentered, the wCorrespondent may
	// be set to zero before time.
	WordList wlMessage(true);
	wlMessage.Set(message);
	for (int i = 0; i < wlMessage.len; i++) {
		// Message format is [:return address:]command:argument
		char *cmd = wlMessage[i];
		if (*cmd == ':') {
			// There is a return address
			char *colon = strchr(cmd + 1, ':');
			if (colon) {
				*colon = '\0';
				wCorrespondent = reinterpret_cast<HWND>(atoi(cmd + 1));
				cmd = colon + 1;
			}
		}
		if (isprefix(cmd, "identity:")) {
			char *arg = strchr(cmd, ':');
			if (arg)
				wDirector = reinterpret_cast<HWND>(atoi(arg + 1));
		} else if (isprefix(cmd, "closing:")) {
			wDirector = 0;
			if (startedByDirector)
				host->ShutDown();
		} else if (host) {
			host->Perform(cmd);
		}
		wCorrespondent = 0;
	}
}

#ifdef _MSC_VER
// Unreferenced inline functions are OK
#pragma warning(disable: 4514)
#endif
<commit_msg>Publishing the frame window handle as the user data of the receiver window.<commit_after>// SciTE - Scintilla based Text Editor
/** @file DirectorExtension.cxx
 ** Extension for communicating with a director program.
 **/
// Copyright 1998-2001 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#include "Platform.h"

#include "PropSet.h"

#include "Scintilla.h"
#include "Accessor.h"
#include "Extender.h"
#include "DirectorExtension.h"
#include "SciTE.h"
#include "SciTEBase.h"

static ExtensionAPI *host = 0;
static DirectorExtension *pde = 0;
static HWND wDirector = 0;
static HWND wCorrespondent = 0;
static HWND wReceiver = 0;
static bool startedByDirector = false;
unsigned int SDI = 0;

static void SendDirector(const char *verb, const char *arg = 0) {
	if ((wDirector != 0) || (wCorrespondent != 0)) {
		HWND wDestination = wCorrespondent;
		SString addressedMessage;
		if (wDestination) {
			addressedMessage += ":";
			SString address(reinterpret_cast<int>(wDestination));
			addressedMessage += address;
			addressedMessage += ":";
		} else {
			wDestination = wDirector;
		}
		addressedMessage += verb;
		addressedMessage += ":";
		if (arg)
			addressedMessage += arg;
		char *slashedMessage = Slash(addressedMessage.c_str());
		if (slashedMessage) {
			COPYDATASTRUCT cds;
			cds.dwData = 0;
			cds.cbData = strlen(slashedMessage);
			cds.lpData = reinterpret_cast<void *>(
			                 const_cast<char *>(slashedMessage));
			::SendMessage(wDestination, WM_COPYDATA,
			              reinterpret_cast<WPARAM>(wReceiver),
			              reinterpret_cast<LPARAM>(&cds));
			delete []slashedMessage;
		}
	}
}

static void SendDirector(const char *verb, sptr_t arg) {
	SString s(arg);
	::SendDirector(verb, s.c_str());
}

static void CheckEnvironment(ExtensionAPI *host) {
	if (!host)
		return ;
	if (!wDirector) {
		char *director = host->Property("director.hwnd");
		if (director && *director) {
			startedByDirector = true;
			wDirector = reinterpret_cast<HWND>(atoi(director));
			// Director is just seen so identify this to it
			::SendDirector("identity", reinterpret_cast<sptr_t>(wReceiver));
		}
		delete []director;
	}
	char number[32];
	sprintf(number, "%0d", reinterpret_cast<int>(wReceiver));
	host->SetProperty("WindowID", number);
}

static char DirectorExtension_ClassName[] = "DirectorExtension";

static LRESULT HandleCopyData(LPARAM lParam) {
	COPYDATASTRUCT *pcds = reinterpret_cast<COPYDATASTRUCT *>(lParam);
	// Copy into an temporary buffer to ensure \0 terminated
	if (pde && pcds->lpData) {
		char *dataCopy = new char[pcds->cbData + 1];
		if (dataCopy) {
			strncpy(dataCopy, reinterpret_cast<char *>(pcds->lpData), pcds->cbData);
			dataCopy[pcds->cbData] = '\0';
			pde->HandleStringMessage(dataCopy);
			delete []dataCopy;
		}
	}
	return 0;
}

LRESULT PASCAL DirectorExtension_WndProc(
    HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam) {
	if (iMessage == WM_COPYDATA) {
		return HandleCopyData(lParam);
	} else if (iMessage == SDI) {
		return SDI;
	}
	return ::DefWindowProc(hWnd, iMessage, wParam, lParam);
}

static void DirectorExtension_Register(HINSTANCE hInstance) {
	WNDCLASS wndclass;
	wndclass.style = 0;
	wndclass.lpfnWndProc = DirectorExtension_WndProc;
	wndclass.cbClsExtra = 0;
	wndclass.cbWndExtra = 0;
	wndclass.hInstance = hInstance;
	wndclass.hIcon = 0;
	wndclass.hCursor = NULL;
	wndclass.hbrBackground = NULL;
	wndclass.lpszMenuName = 0;
	wndclass.lpszClassName = DirectorExtension_ClassName;
	if (!::RegisterClass(&wndclass))
		::exit(FALSE);
}

DirectorExtension::DirectorExtension() {
	pde = this;
}

DirectorExtension::~DirectorExtension() {
	pde = 0;
}

bool DirectorExtension::Initialise(ExtensionAPI *host_) {
	host = host_;
	SDI = ::RegisterWindowMessage("SciTEDirectorInterface");
	HINSTANCE hInstance = reinterpret_cast<HINSTANCE>(
	                          host->GetInstance());
	DirectorExtension_Register(hInstance);
	wReceiver = ::CreateWindow(
	                DirectorExtension_ClassName,
	                DirectorExtension_ClassName,
	                0,
	                0, 0, 0, 0,
	                0,
	                0,
	                hInstance,
	                0);
	if (!wReceiver)
		::exit(FALSE);
	// Make the frame window handle available so the director can activate it.
	::SetWindowLong(wReceiver, GWL_USERDATA,
		reinterpret_cast<LONG>(((SciTEBase*)host)->GetID()));
	CheckEnvironment(host);
	return true;
}

bool DirectorExtension::Finalise() {
	::SendDirector("closing");
	if (wReceiver)
		::DestroyWindow(wReceiver);
	wReceiver = 0;
	return true;
}

bool DirectorExtension::Clear() {
	return true;
}

bool DirectorExtension::Load(const char *) {
	return true;
}

bool DirectorExtension::OnOpen(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("opened", path);
	}
	return true;
}

bool DirectorExtension::OnSwitchFile(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("switched", path);
	}
	return true;
};

bool DirectorExtension::OnSave(const char *path) {
	CheckEnvironment(host);
	if (*path) {
		::SendDirector("saved", path);
	}
	return true;
}

bool DirectorExtension::OnChar(char) {
	return false;
}

bool DirectorExtension::OnExecute(const char *) {
	return false;
}

bool DirectorExtension::OnSavePointReached() {
	return false;
}

bool DirectorExtension::OnSavePointLeft() {
	return false;
}

bool DirectorExtension::OnStyle(unsigned int, int, int, Accessor *) {
	return false;
}

// These should probably have arguments

bool DirectorExtension::OnDoubleClick() {
	return false;
}

bool DirectorExtension::OnUpdateUI() {
	return false;
}

bool DirectorExtension::OnMarginClick() {
	return false;
}

bool DirectorExtension::OnMacro(const char *command, const char *params) {
	SendDirector(command, params);
	return true;
}

bool DirectorExtension::SendProperty(const char *prop) {
	CheckEnvironment(host);
	if (*prop) {
		::SendDirector("property", prop);
	}
	return true;
}

void DirectorExtension::HandleStringMessage(const char *message) {
	// Message may contain multiple commands separated by '\n'
	// Reentrance trouble - if this function is reentered, the wCorrespondent may
	// be set to zero before time.
	WordList wlMessage(true);
	wlMessage.Set(message);
	for (int i = 0; i < wlMessage.len; i++) {
		// Message format is [:return address:]command:argument
		char *cmd = wlMessage[i];
		if (*cmd == ':') {
			// There is a return address
			char *colon = strchr(cmd + 1, ':');
			if (colon) {
				*colon = '\0';
				wCorrespondent = reinterpret_cast<HWND>(atoi(cmd + 1));
				cmd = colon + 1;
			}
		}
		if (isprefix(cmd, "identity:")) {
			char *arg = strchr(cmd, ':');
			if (arg)
				wDirector = reinterpret_cast<HWND>(atoi(arg + 1));
		} else if (isprefix(cmd, "closing:")) {
			wDirector = 0;
			if (startedByDirector)
				host->ShutDown();
		} else if (host) {
			host->Perform(cmd);
		}
		wCorrespondent = 0;
	}
}

#ifdef _MSC_VER
// Unreferenced inline functions are OK
#pragma warning(disable: 4514)
#endif
<|endoftext|>


<commit_before>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * 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 OR COPYRIGHT HOLDERS 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.
 */

/*
 * Description:
 *     What is this file about?
 *
 * Revision history:
 *     xxxx-xx-xx, author, first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include <dsn/tool-api/rpc_address.h>
#include <dsn/tool-api/group_address.h>
#include <dsn/dist/failure_detector_multimaster.h>

namespace dsn {
namespace dist {

slave_failure_detector_with_multimaster::slave_failure_detector_with_multimaster(
    std::vector<::dsn::rpc_address> &meta_servers,
    std::function<void()> &&master_disconnected_callback,
    std::function<void()> &&master_connected_callback)
{
    _meta_servers.assign_group("meta-servers");
    for (auto &s : meta_servers) {
        _meta_servers.group_address()->add(s);
    }

    _meta_servers.group_address()->set_leader(
        meta_servers[random32(0, (uint32_t)meta_servers.size() - 1)]);

    // ATTENTION: here we disable dsn_group_set_update_leader_automatically to avoid
    // failure detecting logic is affected by rpc failure or rpc forwarding.
    _meta_servers.group_address()->set_update_leader_automatically(false);

    _master_disconnected_callback = std::move(master_disconnected_callback);
    _master_connected_callback = std::move(master_connected_callback);
}

slave_failure_detector_with_multimaster::~slave_failure_detector_with_multimaster(void) {}

void slave_failure_detector_with_multimaster::set_leader_for_test(rpc_address meta)
{
    _meta_servers.group_address()->set_leader(meta);
}

void slave_failure_detector_with_multimaster::end_ping(::dsn::error_code err,
                                                       const fd::beacon_ack &ack,
                                                       void *)
{
    dinfo("end ping result, error[%s], time[%" PRId64
          "], ack.this_node[%s], ack.primary_node[%s], ack.is_master[%s], ack.allowed[%s]",
          err.to_string(),
          ack.time,
          ack.this_node.to_string(),
          ack.primary_node.to_string(),
          ack.is_master ? "true" : "false",
          ack.allowed ? "true" : "false");

    service::zauto_lock l(failure_detector::_lock);
    if (!failure_detector::end_ping_internal(err, ack))
        return;

    dassert(ack.this_node == _meta_servers.group_address()->leader(),
            "ack.this_node[%s] vs meta_servers.leader[%s]",
            ack.this_node.to_string(),
            _meta_servers.group_address()->leader().to_string());

    if (ERR_OK != err) {
        rpc_address next = _meta_servers.group_address()->next(ack.this_node);
        if (next != ack.this_node) {
            _meta_servers.group_address()->set_leader(next);
            // do not start next send_beacon() immediately to avoid send rpc too frequently
            switch_master(ack.this_node, next, 1000);
        }
    } else {
        if (ack.is_master) {
            // do nothing
        } else if (ack.primary_node.is_invalid()) {
            rpc_address next = _meta_servers.group_address()->next(ack.this_node);
            if (next != ack.this_node) {
                _meta_servers.group_address()->set_leader(next);
                // do not start next send_beacon() immediately to avoid send rpc too frequently
                switch_master(ack.this_node, next, 1000);
            }
        } else {
            _meta_servers.group_address()->set_leader(ack.primary_node);
            // start next send_beacon() immediately because the leader is possibly right.
            switch_master(ack.this_node, ack.primary_node, 0);
        }
    }
}

// client side
void slave_failure_detector_with_multimaster::on_master_disconnected(
    const std::vector<::dsn::rpc_address> &nodes)
{
    bool primary_disconnected = false;
    rpc_address leader = _meta_servers.group_address()->leader();
    for (auto it = nodes.begin(); it != nodes.end(); ++it) {
        if (leader == *it)
            primary_disconnected = true;
    }

    if (primary_disconnected) {
        _master_disconnected_callback();
    }
}

void slave_failure_detector_with_multimaster::on_master_connected(::dsn::rpc_address node)
{
    /*
    * well, this is called in on_ping_internal, which is called by rep::end_ping.
    * So this function is called in the lock context of fd::_lock
    */
    bool is_primary = (_meta_servers.group_address()->leader() == node);
    if (is_primary) {
        _master_connected_callback();
    }
}
}
} // end namespace
<commit_msg>failure_detector_multimaster: add missing header cinttypes (#14)<commit_after>/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Microsoft Corporation
 *
 * -=- Robust Distributed System Nucleus (rDSN) -=-
 *
 * 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 OR COPYRIGHT HOLDERS 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.
 */

/*
 * Description:
 *     What is this file about?
 *
 * Revision history:
 *     xxxx-xx-xx, author, first version
 *     xxxx-xx-xx, author, fix bug about xxx
 */

#include <cinttypes>
#include <dsn/tool-api/rpc_address.h>
#include <dsn/tool-api/group_address.h>
#include <dsn/dist/failure_detector_multimaster.h>

namespace dsn {
namespace dist {

slave_failure_detector_with_multimaster::slave_failure_detector_with_multimaster(
    std::vector<::dsn::rpc_address> &meta_servers,
    std::function<void()> &&master_disconnected_callback,
    std::function<void()> &&master_connected_callback)
{
    _meta_servers.assign_group("meta-servers");
    for (auto &s : meta_servers) {
        _meta_servers.group_address()->add(s);
    }

    _meta_servers.group_address()->set_leader(
        meta_servers[random32(0, (uint32_t)meta_servers.size() - 1)]);

    // ATTENTION: here we disable dsn_group_set_update_leader_automatically to avoid
    // failure detecting logic is affected by rpc failure or rpc forwarding.
    _meta_servers.group_address()->set_update_leader_automatically(false);

    _master_disconnected_callback = std::move(master_disconnected_callback);
    _master_connected_callback = std::move(master_connected_callback);
}

slave_failure_detector_with_multimaster::~slave_failure_detector_with_multimaster(void) {}

void slave_failure_detector_with_multimaster::set_leader_for_test(rpc_address meta)
{
    _meta_servers.group_address()->set_leader(meta);
}

void slave_failure_detector_with_multimaster::end_ping(::dsn::error_code err,
                                                       const fd::beacon_ack &ack,
                                                       void *)
{
    dinfo("end ping result, error[%s], time[%" PRId64
          "], ack.this_node[%s], ack.primary_node[%s], ack.is_master[%s], ack.allowed[%s]",
          err.to_string(),
          ack.time,
          ack.this_node.to_string(),
          ack.primary_node.to_string(),
          ack.is_master ? "true" : "false",
          ack.allowed ? "true" : "false");

    service::zauto_lock l(failure_detector::_lock);
    if (!failure_detector::end_ping_internal(err, ack))
        return;

    dassert(ack.this_node == _meta_servers.group_address()->leader(),
            "ack.this_node[%s] vs meta_servers.leader[%s]",
            ack.this_node.to_string(),
            _meta_servers.group_address()->leader().to_string());

    if (ERR_OK != err) {
        rpc_address next = _meta_servers.group_address()->next(ack.this_node);
        if (next != ack.this_node) {
            _meta_servers.group_address()->set_leader(next);
            // do not start next send_beacon() immediately to avoid send rpc too frequently
            switch_master(ack.this_node, next, 1000);
        }
    } else {
        if (ack.is_master) {
            // do nothing
        } else if (ack.primary_node.is_invalid()) {
            rpc_address next = _meta_servers.group_address()->next(ack.this_node);
            if (next != ack.this_node) {
                _meta_servers.group_address()->set_leader(next);
                // do not start next send_beacon() immediately to avoid send rpc too frequently
                switch_master(ack.this_node, next, 1000);
            }
        } else {
            _meta_servers.group_address()->set_leader(ack.primary_node);
            // start next send_beacon() immediately because the leader is possibly right.
            switch_master(ack.this_node, ack.primary_node, 0);
        }
    }
}

// client side
void slave_failure_detector_with_multimaster::on_master_disconnected(
    const std::vector<::dsn::rpc_address> &nodes)
{
    bool primary_disconnected = false;
    rpc_address leader = _meta_servers.group_address()->leader();
    for (auto it = nodes.begin(); it != nodes.end(); ++it) {
        if (leader == *it)
            primary_disconnected = true;
    }

    if (primary_disconnected) {
        _master_disconnected_callback();
    }
}

void slave_failure_detector_with_multimaster::on_master_connected(::dsn::rpc_address node)
{
    /*
    * well, this is called in on_ping_internal, which is called by rep::end_ping.
    * So this function is called in the lock context of fd::_lock
    */
    bool is_primary = (_meta_servers.group_address()->leader() == node);
    if (is_primary) {
        _master_connected_callback();
    }
}
}
} // end namespace
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
//
//  File: ProcessPerAlign.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  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 OR COPYRIGHT HOLDERS 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.
//
//  Description: Reorder composites to align periodic boundaries.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
using namespace std;

#include "MeshElements.h"
#include "ProcessPerAlign.h"

#include <LocalRegions/SegExp.h>
#include <LocalRegions/QuadExp.h>
#include <LocalRegions/TriExp.h>
#include <LocalRegions/NodalTriExp.h>
#include <LibUtilities/BasicUtils/SharedArray.hpp>

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey ProcessPerAlign::className =
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eProcessModule, "peralign"),
                ProcessPerAlign::create);

        /**
         * @class ProcessPerAlign
         */

        /**
         * @brief Default constructor.
         */
        ProcessPerAlign::ProcessPerAlign(MeshSharedPtr m) : ProcessModule(m)
        {
            config["surf1"]  = ConfigOption(false, "-1",
                "Tag identifying first surface.");
            config["surf2"]  = ConfigOption(false, "-1",
                "Tag identifying first surface.");
            config["dir"]    = ConfigOption(false, "",
                "Direction in which to align (either x, y, or z)");
            config["orient"] = ConfigOption(true,  "0",
                "Attempt to reorient tets and prisms");
        }

        /**
         * @brief Destructor.
         */
        ProcessPerAlign::~ProcessPerAlign()
        {

        }

        void ProcessPerAlign::Process()
        {
            static int tetFaceNodes[4][3] = {
                {0,1,2},{0,1,3},{1,2,3},{0,2,3}};

            int    surf1  = config["surf1"]. as<int>   ();
            int    surf2  = config["surf2"]. as<int>   ();
            string dir    = config["dir"].   as<string>();
            bool   orient = config["orient"].as<bool>  ();

            if (surf1 == -1)
            {
                cerr << "WARNING: surf1 must be set to a positive integer. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            if (surf2 == -1)
            {
                cerr << "WARNING: surf2 must be set to a positive integer. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            if (dir != "x" && dir != "y" && dir != "z")
            {
                cerr << "WARNING: dir must be set to either x, y or z. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            NekDouble vec[3];
            vec[0] = dir == "x" ? 1.0 : 0.0;
            vec[1] = dir == "y" ? 1.0 : 0.0;
            vec[2] = dir == "z" ? 1.0 : 0.0;

            CompositeMap::iterator it1 = m->composite.find(surf1);
            CompositeMap::iterator it2 = m->composite.find(surf2);

            if (it1 == m->composite.end())
            {
                cerr << "WARNING: Couldn't find surface " << surf1
                     << ". Skipping periodic alignment." << endl;
                return;
            }

            if (it2 == m->composite.end())
            {
                cerr << "WARNING: Couldn't find surface " << surf2 << ", "
                     << "skipping periodic alignment." << endl;
                return;
            }

            CompositeSharedPtr c1 = it1->second;
            CompositeSharedPtr c2 = it2->second;

            if (c1->items.size() != c2->items.size())
            {
                cerr << "WARNING: Surfaces " << surf1 << " and " << surf2
                     << " have different numbers of elements. Skipping periodic"
                     << " alignment." << endl;
                return;
            }

            c1->reorder = false;
            c2->reorder = false;

            map<int, pair<FaceSharedPtr, vector<int> > > perFaces;

            // Loop over elements, calculate centroids of elements in c2.
            map<int, Node> centroidMap;
            map<int, Node>::iterator it;
            for (int i = 0; i < c2->items.size(); ++i)
            {
                Node centroid;
                for (int j = 0; j < c2->items[i]->GetVertexCount(); ++j)
                {
                    centroid += *(c2->items[i]->GetVertex(j));
                }
                centroid /= (NekDouble)c2->items[i]->GetVertexCount();
                centroidMap[i] = centroid;
            }

            boost::unordered_set<int> elmtDone;
            map<int, int> elmtPairs;
            map<int, int> vertCheck;

            for (int i = 0; i < c1->items.size(); ++i)
            {
                Node centroid;
                for (int j = 0; j < c1->items[i]->GetVertexCount(); ++j)
                {
                    centroid += *(c1->items[i]->GetVertex(j));
                }
                centroid /= (NekDouble)c1->items[i]->GetVertexCount();

                for (it = centroidMap.begin(); it != centroidMap.end(); ++it)
                {
                    if (elmtDone.count(it->first) > 0)
                    {
                        continue;
                    }

                    Node dx = it->second - centroid;
                    if (fabs(fabs(dx.x*vec[0] + dx.y*vec[1] + dx.z*vec[2])/
                             sqrt(dx.abs2()) - 1.0) < 1e-6)
                    {
                        // Found match
                        int id1 = c1->items[i]        ->GetFaceLink()->id;
                        int id2 = c2->items[it->first]->GetFaceLink()->id;

                        elmtDone.insert(it->first);
                        elmtPairs[i] = it->first;

                        // Identify periodic vertices
                        int nVerts = c1->items[i]->GetVertexCount();
                        vector<int> perVerts(nVerts, 0), perVertsInv(nVerts, 0);

                        for (int k = 0; k < nVerts; ++k)
                        {
                            NodeSharedPtr n1 = c1->items[i]->GetFaceLink()->vertexList[k];
                            int l;

                            for (l = 0; l < nVerts; ++l)
                            {
                                NodeSharedPtr n2 =
                                    c2->items[it->first]->GetFaceLink()->vertexList[l];

                                Node dn = *n2 - *n1;
                                if (fabs(fabs(dn.x*vec[0] + dn.y*vec[1] +
                                              dn.z*vec[2])/
                                         sqrt(dn.abs2()) - 1.0) < 1e-6)
                                {
                                    perVerts   [k] = l;
                                    perVertsInv[l] = k;

                                    int id1 = n1->id;
                                    int id2 = n2->id;
                                    if (vertCheck.count(id1) == 0)
                                    {
                                        vertCheck[id1] = id2;
                                    }
                                    else
                                    {
                                        ASSERTL0(vertCheck[id1] == id2,
                                                 "Periodic vertex already "
                                                 "identified!");
                                    }
                                    break;
                                }
                            }
                            ASSERTL1(l < nVerts,
                                     "Could not identify periodic vertices.");
                        }

                        int tot1 = 0, tot2 = 0;
                        for (int k = 0; k < nVerts; ++k)
                        {
                            tot1 += perVerts   [k];
                            tot2 += perVertsInv[k];
                        }

                        ASSERTL0(tot1 == nVerts*(nVerts-1)/2 &&
                                 tot2 == nVerts*(nVerts-1)/2,
                                 "Error identifying periodic vertices");

                        perFaces[id1] = make_pair(
                            c2->items[it->first]->GetFaceLink(), perVerts);
                        perFaces[id2] = make_pair(
                            c1->items[i]        ->GetFaceLink(), perVertsInv);
                        break;
                    }
                }

                if (it == centroidMap.end())
                {
                    cerr << "WARNING: Could not find matching edge for surface "
                         << "element " << c1->items[i]->GetId() << ". "
                         << "Skipping periodic alignment." << endl;
                    return;
                }
            }

            // Reorder vectors.
            vector<ElementSharedPtr> tmp = c2->items;

            map<int, int>::iterator mIt;

            for (int i = 0; i < tmp.size(); ++i)
            {
                c2->items[i] = tmp[elmtPairs[i]];
            }

            if (orient)
            {
                ReorderPrisms(perFaces);
            }
        }
    }
}
<commit_msg>Disable identification of periodic vertices when orient is disabled.<commit_after>////////////////////////////////////////////////////////////////////////////////
//
//  File: ProcessPerAlign.cpp
//
//  For more information, please see: http://www.nektar.info/
//
//  The MIT License
//
//  Copyright (c) 2006 Division of Applied Mathematics, Brown University (USA),
//  Department of Aeronautics, Imperial College London (UK), and Scientific
//  Computing and Imaging Institute, University of Utah (USA).
//
//  License for the specific language governing rights and limitations under
//  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 OR COPYRIGHT HOLDERS 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.
//
//  Description: Reorder composites to align periodic boundaries.
//
////////////////////////////////////////////////////////////////////////////////

#include <string>
using namespace std;

#include "MeshElements.h"
#include "ProcessPerAlign.h"

#include <LocalRegions/SegExp.h>
#include <LocalRegions/QuadExp.h>
#include <LocalRegions/TriExp.h>
#include <LocalRegions/NodalTriExp.h>
#include <LibUtilities/BasicUtils/SharedArray.hpp>

namespace Nektar
{
    namespace Utilities
    {
        ModuleKey ProcessPerAlign::className =
            GetModuleFactory().RegisterCreatorFunction(
                ModuleKey(eProcessModule, "peralign"),
                ProcessPerAlign::create);

        /**
         * @class ProcessPerAlign
         */

        /**
         * @brief Default constructor.
         */
        ProcessPerAlign::ProcessPerAlign(MeshSharedPtr m) : ProcessModule(m)
        {
            config["surf1"]  = ConfigOption(false, "-1",
                "Tag identifying first surface.");
            config["surf2"]  = ConfigOption(false, "-1",
                "Tag identifying first surface.");
            config["dir"]    = ConfigOption(false, "",
                "Direction in which to align (either x, y, or z)");
            config["orient"] = ConfigOption(true,  "0",
                "Attempt to reorient tets and prisms");
        }

        /**
         * @brief Destructor.
         */
        ProcessPerAlign::~ProcessPerAlign()
        {

        }

        void ProcessPerAlign::Process()
        {
            static int tetFaceNodes[4][3] = {
                {0,1,2},{0,1,3},{1,2,3},{0,2,3}};

            int    surf1  = config["surf1"]. as<int>   ();
            int    surf2  = config["surf2"]. as<int>   ();
            string dir    = config["dir"].   as<string>();
            bool   orient = config["orient"].as<bool>  ();

            if (surf1 == -1)
            {
                cerr << "WARNING: surf1 must be set to a positive integer. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            if (surf2 == -1)
            {
                cerr << "WARNING: surf2 must be set to a positive integer. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            if (dir != "x" && dir != "y" && dir != "z")
            {
                cerr << "WARNING: dir must be set to either x, y or z. "
                     << "Skipping periodic alignment." << endl;
                return;
            }

            NekDouble vec[3];
            vec[0] = dir == "x" ? 1.0 : 0.0;
            vec[1] = dir == "y" ? 1.0 : 0.0;
            vec[2] = dir == "z" ? 1.0 : 0.0;

            CompositeMap::iterator it1 = m->composite.find(surf1);
            CompositeMap::iterator it2 = m->composite.find(surf2);

            if (it1 == m->composite.end())
            {
                cerr << "WARNING: Couldn't find surface " << surf1
                     << ". Skipping periodic alignment." << endl;
                return;
            }

            if (it2 == m->composite.end())
            {
                cerr << "WARNING: Couldn't find surface " << surf2 << ", "
                     << "skipping periodic alignment." << endl;
                return;
            }

            CompositeSharedPtr c1 = it1->second;
            CompositeSharedPtr c2 = it2->second;

            if (c1->items.size() != c2->items.size())
            {
                cerr << "WARNING: Surfaces " << surf1 << " and " << surf2
                     << " have different numbers of elements. Skipping periodic"
                     << " alignment." << endl;
                return;
            }

            c1->reorder = false;
            c2->reorder = false;

            map<int, pair<FaceSharedPtr, vector<int> > > perFaces;

            // Loop over elements, calculate centroids of elements in c2.
            map<int, Node> centroidMap;
            map<int, Node>::iterator it;
            for (int i = 0; i < c2->items.size(); ++i)
            {
                Node centroid;
                for (int j = 0; j < c2->items[i]->GetVertexCount(); ++j)
                {
                    centroid += *(c2->items[i]->GetVertex(j));
                }
                centroid /= (NekDouble)c2->items[i]->GetVertexCount();
                centroidMap[i] = centroid;
            }

            boost::unordered_set<int> elmtDone;
            map<int, int> elmtPairs;
            map<int, int> vertCheck;

            for (int i = 0; i < c1->items.size(); ++i)
            {
                Node centroid;
                for (int j = 0; j < c1->items[i]->GetVertexCount(); ++j)
                {
                    centroid += *(c1->items[i]->GetVertex(j));
                }
                centroid /= (NekDouble)c1->items[i]->GetVertexCount();

                for (it = centroidMap.begin(); it != centroidMap.end(); ++it)
                {
                    if (elmtDone.count(it->first) > 0)
                    {
                        continue;
                    }

                    Node dx = it->second - centroid;
                    if (fabs(fabs(dx.x*vec[0] + dx.y*vec[1] + dx.z*vec[2])/
                             sqrt(dx.abs2()) - 1.0) < 1e-6)
                    {
                        // Found match
                        int id1 = c1->items[i]        ->GetFaceLink()->id;
                        int id2 = c2->items[it->first]->GetFaceLink()->id;

                        elmtDone.insert(it->first);
                        elmtPairs[i] = it->first;

                        // Identify periodic vertices
                        int nVerts = c1->items[i]->GetVertexCount();
                        vector<int> perVerts(nVerts, 0), perVertsInv(nVerts, 0);

                        if (orient)
                        {
                            for (int k = 0; k < nVerts; ++k)
                            {
                                NodeSharedPtr n1 = c1->items[i]->GetFaceLink()->vertexList[k];
                                int l;

                                for (l = 0; l < nVerts; ++l)
                                {
                                    NodeSharedPtr n2 =
                                        c2->items[it->first]->GetFaceLink()->vertexList[l];

                                    Node dn = *n2 - *n1;
                                    if (fabs(fabs(dn.x*vec[0] + dn.y*vec[1] +
                                                  dn.z*vec[2])/
                                             sqrt(dn.abs2()) - 1.0) < 1e-6)
                                    {
                                        perVerts   [k] = l;
                                        perVertsInv[l] = k;

                                        int id1 = n1->id;
                                        int id2 = n2->id;
                                        if (vertCheck.count(id1) == 0)
                                        {
                                            vertCheck[id1] = id2;
                                        }
                                        else
                                        {
                                            ASSERTL0(vertCheck[id1] == id2,
                                                     "Periodic vertex already "
                                                     "identified!");
                                        }
                                        break;
                                    }
                                }
                                ASSERTL1(l < nVerts,
                                         "Could not identify periodic vertices.");
                            }

                            int tot1 = 0, tot2 = 0;
                            for (int k = 0; k < nVerts; ++k)
                            {
                                tot1 += perVerts   [k];
                                tot2 += perVertsInv[k];
                            }
                            ASSERTL0(tot1 == nVerts*(nVerts-1)/2 &&
                                     tot2 == nVerts*(nVerts-1)/2,
                                     "Error identifying periodic vertices");
                        }

                        perFaces[id1] = make_pair(
                            c2->items[it->first]->GetFaceLink(), perVerts);
                        perFaces[id2] = make_pair(
                            c1->items[i]        ->GetFaceLink(), perVertsInv);
                        break;
                    }
                }

                if (it == centroidMap.end())
                {
                    cerr << "WARNING: Could not find matching edge for surface "
                         << "element " << c1->items[i]->GetId() << ". "
                         << "Skipping periodic alignment." << endl;
                    return;
                }
            }

            // Reorder vectors.
            vector<ElementSharedPtr> tmp = c2->items;

            map<int, int>::iterator mIt;

            for (int i = 0; i < tmp.size(); ++i)
            {
                c2->items[i] = tmp[elmtPairs[i]];
            }

            if (orient)
            {
                ReorderPrisms(perFaces);
            }
        }
    }
}
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.
 *
 *=========================================================================*/

#include "itkHessianRecursiveGaussianImageFilter.h"
#include "itkSheetnessMeasureImageFilter.h"
#include "itkAngleOfIncidenceImageFilter.h"
#include "itkImageFileWriter.h"
#include "itkImageFileReader.h"
#include "itkThresholdImageFilter.h"

int itkAngleOfIncidenceImageFilterTest(int argc ,char* argv [] )
{
  // Argument parsing.
  if( argc < 7 )
    {
    std::cerr << "Missing arguments." << std::endl;
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << " Input_Ultrasound_Image Output_Sheetness_Image Output_Angle_Of_Incidence_Image UltrasoundOriginX UltrasoundOrignY UltrasoundOriginZ" << std::endl;
    return EXIT_FAILURE;
    }

  // Types.
  static const unsigned int Dimension = 3;

  typedef unsigned short                              UltrasoundPixelType;
  typedef itk::Image< UltrasoundPixelType, Dimension > UltrasoundImageType;

  typedef float                                              AngleOfIncidencePixelType;
  typedef itk::Image< AngleOfIncidencePixelType, Dimension > AngleOfIncidenceImageType;

  // Reader,
  typedef itk::ImageFileReader< UltrasoundImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[1] );

  // Declare the type for the Hessian filter
  typedef itk::HessianRecursiveGaussianImageFilter< UltrasoundImageType >  HessianFilterType;

  // Declare the type for the sheetness measure filter
  typedef itk::SheetnessMeasureImageFilter< float >  SheetnessMeasureImageFilterType;

  // Create a Hessian Filter
  HessianFilterType::Pointer filterHessian = HessianFilterType::New();

  // Create a sheetness Filter
  SheetnessMeasureImageFilterType::Pointer filterSheetness = SheetnessMeasureImageFilterType::New();

  // Connect the input images
  filterHessian->SetInput( reader->GetOutput() );
  filterSheetness->SetInput( filterHessian->GetOutput() );

  // Select the value of Sigma
  filterHessian->SetSigma( 0.5 );

  // Execute the filter
  std::cout << "Generate sheetness measure" << std::endl;
  filterSheetness->Update();

  //Write out the sheetness image
  typedef SheetnessMeasureImageFilterType::OutputImageType SheetnessImageType;

  typedef itk::ImageFileWriter<SheetnessImageType>     SheetnessImageWriterType;
  SheetnessImageWriterType::Pointer writer= SheetnessImageWriterType::New();
  std::cout<< "Writing out sheetness measure image" << std::endl;
  writer->SetFileName(argv[2]);
  writer->SetInput(filterSheetness->GetOutput());
  writer->Update();

  //Generate a binary image by threshlding the sheetness measure
  typedef itk::ThresholdImageFilter< SheetnessImageType >  ThresholdFilterType;

  ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
  thresholdFilter->SetInput( filterSheetness->GetOutput());
  thresholdFilter->SetOutsideValue( 0 );
  thresholdFilter->ThresholdBelow ( 180 );
  thresholdFilter->Update();

  //Compute the angle of incidence measure
  typedef itk::AngleOfIncidenceImageFilter
        < SheetnessImageType, AngleOfIncidenceImageType >   AngleOfIncidenceImageFilterType;

  // Create a sheetness Filter
  AngleOfIncidenceImageFilterType::Pointer filterAngleOfIncidence = AngleOfIncidenceImageFilterType::New();

  //Read in the ultrasound probe origin (X,Y,Z)
  double UltrasoundProbeOriginX = atof( argv[4] );
  double UltrasoundProbeOriginY = atof( argv[5] );
  double UltrasoundProbeOriginZ = atof( argv[6] );

  itk::Vector< double, 3 > UltrasoundProbeOriginVector;

  UltrasoundProbeOriginVector[0] = UltrasoundProbeOriginX;
  UltrasoundProbeOriginVector[1] = UltrasoundProbeOriginY;
  UltrasoundProbeOriginVector[0] = UltrasoundProbeOriginZ;

  filterAngleOfIncidence->SetUltrasoundProbeOrigin( UltrasoundProbeOriginVector );
  filterAngleOfIncidence->SetInput( thresholdFilter->GetOutput() );

  //Write out the Angle of Incidence image
  typedef AngleOfIncidenceImageFilterType::OutputImageType AngleOfIncidencesImageType;
  typedef itk::ImageFileWriter<AngleOfIncidencesImageType>     AngleOfIncidencesImageWriterType;
  AngleOfIncidencesImageWriterType::Pointer angleOfIncidenceWriter= AngleOfIncidencesImageWriterType::New();
  std::cout<< "Writing out angle of incidence measure image" << std::endl;
  angleOfIncidenceWriter->SetFileName(argv[3]);
  angleOfIncidenceWriter->SetInput(filterAngleOfIncidence->GetOutput());
  angleOfIncidenceWriter->Update();

  return EXIT_SUCCESS;

}
<commit_msg>BUG: Fix index error for ultrasound origin vector<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.
 *
 *=========================================================================*/

#include "itkHessianRecursiveGaussianImageFilter.h"
#include "itkSheetnessMeasureImageFilter.h"
#include "itkAngleOfIncidenceImageFilter.h"
#include "itkImageFileWriter.h"
#include "itkImageFileReader.h"
#include "itkThresholdImageFilter.h"

int itkAngleOfIncidenceImageFilterTest(int argc ,char* argv [] )
{
  // Argument parsing.
  if( argc < 7 )
    {
    std::cerr << "Missing arguments." << std::endl;
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << " Input_Ultrasound_Image Output_Sheetness_Image Output_Angle_Of_Incidence_Image UltrasoundOriginX UltrasoundOrignY UltrasoundOriginZ" << std::endl;
    return EXIT_FAILURE;
    }

  // Types.
  static const unsigned int Dimension = 3;

  typedef unsigned short                              UltrasoundPixelType;
  typedef itk::Image< UltrasoundPixelType, Dimension > UltrasoundImageType;

  typedef float                                              AngleOfIncidencePixelType;
  typedef itk::Image< AngleOfIncidencePixelType, Dimension > AngleOfIncidenceImageType;

  // Reader,
  typedef itk::ImageFileReader< UltrasoundImageType > ReaderType;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName( argv[1] );

  // Declare the type for the Hessian filter
  typedef itk::HessianRecursiveGaussianImageFilter< UltrasoundImageType >  HessianFilterType;

  // Declare the type for the sheetness measure filter
  typedef itk::SheetnessMeasureImageFilter< float >  SheetnessMeasureImageFilterType;

  // Create a Hessian Filter
  HessianFilterType::Pointer filterHessian = HessianFilterType::New();

  // Create a sheetness Filter
  SheetnessMeasureImageFilterType::Pointer filterSheetness = SheetnessMeasureImageFilterType::New();

  // Connect the input images
  filterHessian->SetInput( reader->GetOutput() );
  filterSheetness->SetInput( filterHessian->GetOutput() );

  // Select the value of Sigma
  filterHessian->SetSigma( 0.5 );

  // Execute the filter
  std::cout << "Generate sheetness measure" << std::endl;
  filterSheetness->Update();

  //Write out the sheetness image
  typedef SheetnessMeasureImageFilterType::OutputImageType SheetnessImageType;

  typedef itk::ImageFileWriter<SheetnessImageType>     SheetnessImageWriterType;
  SheetnessImageWriterType::Pointer writer= SheetnessImageWriterType::New();
  std::cout<< "Writing out sheetness measure image" << std::endl;
  writer->SetFileName(argv[2]);
  writer->SetInput(filterSheetness->GetOutput());
  writer->Update();

  //Generate a binary image by threshlding the sheetness measure
  typedef itk::ThresholdImageFilter< SheetnessImageType >  ThresholdFilterType;

  ThresholdFilterType::Pointer thresholdFilter = ThresholdFilterType::New();
  thresholdFilter->SetInput( filterSheetness->GetOutput());
  thresholdFilter->SetOutsideValue( 0 );
  thresholdFilter->ThresholdBelow ( 180 );
  thresholdFilter->Update();

  //Compute the angle of incidence measure
  typedef itk::AngleOfIncidenceImageFilter
        < SheetnessImageType, AngleOfIncidenceImageType >   AngleOfIncidenceImageFilterType;

  // Create a sheetness Filter
  AngleOfIncidenceImageFilterType::Pointer filterAngleOfIncidence = AngleOfIncidenceImageFilterType::New();

  //Read in the ultrasound probe origin (X,Y,Z)
  double UltrasoundProbeOriginX = atof( argv[4] );
  double UltrasoundProbeOriginY = atof( argv[5] );
  double UltrasoundProbeOriginZ = atof( argv[6] );

  itk::Vector< double, 3 > UltrasoundProbeOriginVector;

  UltrasoundProbeOriginVector[0] = UltrasoundProbeOriginX;
  UltrasoundProbeOriginVector[1] = UltrasoundProbeOriginY;
  UltrasoundProbeOriginVector[2] = UltrasoundProbeOriginZ;

  filterAngleOfIncidence->SetUltrasoundProbeOrigin( UltrasoundProbeOriginVector );
  filterAngleOfIncidence->SetInput( thresholdFilter->GetOutput() );

  //Write out the Angle of Incidence image
  typedef AngleOfIncidenceImageFilterType::OutputImageType AngleOfIncidencesImageType;
  typedef itk::ImageFileWriter<AngleOfIncidencesImageType>     AngleOfIncidencesImageWriterType;
  AngleOfIncidencesImageWriterType::Pointer angleOfIncidenceWriter= AngleOfIncidencesImageWriterType::New();
  std::cout<< "Writing out angle of incidence measure image" << std::endl;
  angleOfIncidenceWriter->SetFileName(argv[3]);
  angleOfIncidenceWriter->SetInput(filterAngleOfIncidence->GetOutput());
  angleOfIncidenceWriter->Update();

  return EXIT_SUCCESS;

}
<|endoftext|>