<commit_before>/* perform smoothing using an anisotropic diffusion filter */

#include "itkVVFilterModule.h"

#include "itkGradientAnisotropicDiffusionImageFilter.h"

static int ProcessData(void *inf, vtkVVProcessDataStruct *pds)
{

  vtkVVPluginInfo *info = (vtkVVPluginInfo *)inf;

  const unsigned int Dimension = 3;

  typedef   float       InternalPixelType;
  typedef   itk::Image< InternalPixelType,Dimension > InternalImageType;

  typedef   itk::GradientAnisotropicDiffusionImageFilter<
                                InternalImageType,
                                InternalImageType >   FilterType;

  try
  {
  switch( info->InputVolumeScalarType )
    {
    case VTK_UNSIGNED_CHAR:
      {
      FilterModule< unsigned char, FilterType > module;
      module.SetPlugInfo( info );
      module.SetUpdateMessage("Smoothing with Gradient Anisotropic Diffusion...");
      // Set the parameters on it
      module.GetFilter()->SetIterations(             atoi( info->GUIItems[ 0 ].CurrentValue) );
      module.GetFilter()->SetConductanceParameter(   atof( info->GUIItems[ 1 ].CurrentValue) );
      module.SetNeedCasting( true );
      // Execute the filter
      module.ProcessData( pds  );
      break;
      }
    case VTK_UNSIGNED_SHORT:
      {
      FilterModule< unsigned short, FilterType > module;
      module.SetPlugInfo( info );
      module.SetUpdateMessage("Smoothing with Gradient Anisotropic Diffusion...");
      // Set the parameters on it
      module.GetFilter()->SetIterations(             atoi( info->GUIItems[ 0 ].CurrentValue) );
      module.GetFilter()->SetConductanceParameter(   atof( info->GUIItems[ 1 ].CurrentValue) );
      module.SetNeedCasting( true );
      // Execute the filter
      module.ProcessData( pds );
      break;
      }
    }
  }
  catch( itk::ExceptionObject & except )
  {
    info->DisplayError( info, except.what() );
    return -1;
  }
  return 0;
}

static int UpdateGUI(void *inf)
{
  vtkVVPluginInfo *info = (vtkVVPluginInfo *)inf;

  info->GUIItems[0].Label = "Number of Iterations";
  info->GUIItems[0].GUIType = VV_GUI_SCALE;
  info->GUIItems[0].Default = "5";
  info->GUIItems[0].Help = "Number of times that the diffusion approximation will be computed. The more iterations, the stronger the smoothing";
  info->GUIItems[0].Hints = "1 100 1";

  info->GUIItems[1].Label = "Conductance";
  info->GUIItems[1].GUIType = VV_GUI_SCALE;
  info->GUIItems[1].Default = "3.0";
  info->GUIItems[1].Help = "Factor that multiplies the image gradient in order to compute the effective conductance locally. The higher the value of this parameter, the stronger the diffusion will be";
  info->GUIItems[1].Hints = "0.1 10.0 0.1";

  info->RequiredZOverlap = 0;

  info->OutputVolumeScalarType = info->InputVolumeScalarType;
  info->OutputVolumeNumberOfComponents =
    info->InputVolumeNumberOfComponents;
  memcpy(info->OutputVolumeDimensions,info->InputVolumeDimensions,
         3*sizeof(int));
  memcpy(info->OutputVolumeSpacing,info->InputVolumeSpacing,
         3*sizeof(float));
  memcpy(info->OutputVolumeOrigin,info->InputVolumeOrigin,
         3*sizeof(float));

  return 1;
}

extern "C" {

void VV_PLUGIN_EXPORT vvGradientAnisotropicDiffusionInit(vtkVVPluginInfo *info)
{
  // setup information that never changes
  info->ProcessData = ProcessData;
  info->UpdateGUI = UpdateGUI;
  info->Name = "Gradient Anisotropic Diffusion";
  info->TerseDocumentation = "Anisotropic diffusion smoothing";
  info->FullDocumentation =
    "This filter applies an edge-preserving smoothing to a volume by computing the evolution of an anisotropic diffusion partial differential equation. Diffusion is regulated by the gradient of the image. This filter processes the whole image in one piece, and does not change the dimensions, data type, or spacing of the volume.";
  info->SupportsInPlaceProcessing = 0;
  info->SupportsProcessingPieces = 0;
  info->RequiredZOverlap = 0;

  /* setup the GUI components */
  info->NumberOfGUIItems = 2;
  info->GUIItems = (vtkVVGUIItem *)malloc(info->NumberOfGUIItems*sizeof(vtkVVGUIItem));
}

}
<commit_msg>ENH: TimeStep parameter is back after confirmation from Josh that the      parameter is still needed.<commit_after>/* perform smoothing using an anisotropic diffusion filter */

#include "itkVVFilterModule.h"

#include "itkGradientAnisotropicDiffusionImageFilter.h"

static int ProcessData(void *inf, vtkVVProcessDataStruct *pds)
{

  vtkVVPluginInfo *info = (vtkVVPluginInfo *)inf;

  const unsigned int Dimension = 3;

  typedef   float       InternalPixelType;
  typedef   itk::Image< InternalPixelType,Dimension > InternalImageType;

  typedef   itk::GradientAnisotropicDiffusionImageFilter<
                                InternalImageType,
                                InternalImageType >   FilterType;

  try
  {
  switch( info->InputVolumeScalarType )
    {
    case VTK_UNSIGNED_CHAR:
      {
      FilterModule< unsigned char, FilterType > module;
      module.SetPlugInfo( info );
      module.SetUpdateMessage("Smoothing with Gradient Anisotropic Diffusion...");
      // Set the parameters on it
      module.GetFilter()->SetIterations(             atoi( info->GUIItems[ 0 ].CurrentValue) );
      module.GetFilter()->SetTimeStep(               atof( info->GUIItems[ 1 ].CurrentValue) );
      module.GetFilter()->SetConductanceParameter(   atof( info->GUIItems[ 2 ].CurrentValue) );
      module.SetNeedCasting( true );
      // Execute the filter
      module.ProcessData( pds  );
      break;
      }
    case VTK_UNSIGNED_SHORT:
      {
      FilterModule< unsigned short, FilterType > module;
      module.SetPlugInfo( info );
      module.SetUpdateMessage("Smoothing with Gradient Anisotropic Diffusion...");
      // Set the parameters on it
      module.GetFilter()->SetIterations(             atoi( info->GUIItems[ 0 ].CurrentValue) );
      module.GetFilter()->SetTimeStep(               atof( info->GUIItems[ 1 ].CurrentValue) );
      module.GetFilter()->SetConductanceParameter(   atof( info->GUIItems[ 2 ].CurrentValue) );
      module.SetNeedCasting( true );
      // Execute the filter
      module.ProcessData( pds );
      break;
      }
    }
  }
  catch( itk::ExceptionObject & except )
  {
    info->DisplayError( info, except.what() );
    return -1;
  }
  return 0;
}

static int UpdateGUI(void *inf)
{
  vtkVVPluginInfo *info = (vtkVVPluginInfo *)inf;

  info->GUIItems[0].Label = "Number of Iterations";
  info->GUIItems[0].GUIType = VV_GUI_SCALE;
  info->GUIItems[0].Default = "5";
  info->GUIItems[0].Help = "Number of times that the diffusion approximation will be computed. The more iterations, the stronger the smoothing";
  info->GUIItems[0].Hints = "1 100 1";

  info->GUIItems[1].Label = "Time Step";
  info->GUIItems[1].GUIType = VV_GUI_SCALE;
  info->GUIItems[1].Default = "0.125";
  info->GUIItems[1].Help = "Discretization of time for approximating the diffusion process.";
  info->GUIItems[1].Hints = "0.01 1.0 0.005";

  info->GUIItems[2].Label = "Conductance";
  info->GUIItems[2].GUIType = VV_GUI_SCALE;
  info->GUIItems[2].Default = "3.0";
  info->GUIItems[2].Help = "Factor that multiplies the image gradient in order to compute the effective conductance locally. The higher the value of this parameter, the stronger the diffusion will be";
  info->GUIItems[2].Hints = "0.1 10.0 0.1";

  info->RequiredZOverlap = 0;

  info->OutputVolumeScalarType = info->InputVolumeScalarType;
  info->OutputVolumeNumberOfComponents =
    info->InputVolumeNumberOfComponents;
  memcpy(info->OutputVolumeDimensions,info->InputVolumeDimensions,
         3*sizeof(int));
  memcpy(info->OutputVolumeSpacing,info->InputVolumeSpacing,
         3*sizeof(float));
  memcpy(info->OutputVolumeOrigin,info->InputVolumeOrigin,
         3*sizeof(float));

  return 1;
}

extern "C" {

void VV_PLUGIN_EXPORT vvGradientAnisotropicDiffusionInit(vtkVVPluginInfo *info)
{
  // setup information that never changes
  info->ProcessData = ProcessData;
  info->UpdateGUI = UpdateGUI;
  info->Name = "Gradient Anisotropic Diffusion";
  info->TerseDocumentation = "Anisotropic diffusion smoothing";
  info->FullDocumentation =
    "This filter applies an edge-preserving smoothing to a volume by computing the evolution of an anisotropic diffusion partial differential equation. Diffusion is regulated by the gradient of the image. This filter processes the whole image in one piece, and does not change the dimensions, data type, or spacing of the volume.";
  info->SupportsInPlaceProcessing = 0;
  info->SupportsProcessingPieces = 0;
  info->RequiredZOverlap = 0;

  /* setup the GUI components */
  info->NumberOfGUIItems = 3;
  info->GUIItems = (vtkVVGUIItem *)malloc(info->NumberOfGUIItems*sizeof(vtkVVGUIItem));
}

}
<|endoftext|>


<commit_before>//===--- Dexp.cpp - Dex EXPloration tool ------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interactive tool which can be used to manually
// evaluate symbol search quality of Clangd index.
//
//===----------------------------------------------------------------------===//

#include "SourceCode.h"
#include "index/Serialization.h"
#include "index/dex/Dex.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/LineEditor/LineEditor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"

using namespace llvm;
using namespace clang;
using namespace clangd;

namespace {

cl::opt<std::string> IndexPath("index-path", cl::desc("Path to the index"),
                               cl::Positional, cl::Required);

static const std::string Overview = R"(
This is an **experimental** interactive tool to process user-provided search
queries over given symbol collection obtained via clangd-indexer. The
tool can be used to evaluate search quality of existing index implementations
and manually construct non-trivial test cases.

Type use "help" request to get information about the details.
)";

void reportTime(StringRef Name, function_ref<void()> F) {
  const auto TimerStart = std::chrono::high_resolution_clock::now();
  F();
  const auto TimerStop = std::chrono::high_resolution_clock::now();
  const auto Duration = std::chrono::duration_cast<std::chrono::milliseconds>(
      TimerStop - TimerStart);
  outs() << formatv("{0} took {1:ms+n}.\n", Name, Duration);
}

std::vector<SymbolID> getSymbolIDsFromIndex(StringRef QualifiedName,
                                            const SymbolIndex *Index) {
  FuzzyFindRequest Request;
  // Remove leading "::" qualifier as FuzzyFind doesn't need leading "::"
  // qualifier for global scope.
  bool IsGlobalScope = QualifiedName.consume_front("::");
  auto Names = splitQualifiedName(QualifiedName);
  if (IsGlobalScope || !Names.first.empty())
    Request.Scopes = {Names.first};
  else
    // QualifiedName refers to a symbol in global scope (e.g. "GlobalSymbol"),
    // add the global scope to the request.
    Request.Scopes = {""};

  Request.Query = Names.second;
  std::vector<SymbolID> SymIDs;
  Index->fuzzyFind(Request, [&](const Symbol &Sym) {
    std::string SymQualifiedName = (Sym.Scope + Sym.Name).str();
    if (QualifiedName == SymQualifiedName)
      SymIDs.push_back(Sym.ID);
  });
  return SymIDs;
}

// REPL commands inherit from Command and contain their options as members.
// Creating a Command populates parser options, parseAndRun() resets them.
class Command {
  // By resetting the parser options, we lost the standard -help flag.
  cl::opt<bool, false, cl::parser<bool>> Help{
      "help", cl::desc("Display available options"), cl::ValueDisallowed,
      cl::cat(cl::GeneralCategory)};
  virtual void run() = 0;

protected:
  const SymbolIndex *Index;

public:
  virtual ~Command() = default;
  virtual void parseAndRun(ArrayRef<const char *> Argv, const char *Overview,
                           const SymbolIndex &Index) {
    std::string ParseErrs;
    raw_string_ostream OS(ParseErrs);
    bool Ok =
        cl::ParseCommandLineOptions(Argv.size(), Argv.data(), Overview, &OS);
    if (Help.getNumOccurrences() > 0) {
      // Avoid printing parse errors in this case.
      // (Well, in theory. A bunch get printed to llvm::errs() regardless!)
      cl::PrintHelpMessage();
    } else {
      outs() << OS.str();
      if (Ok) {
        this->Index = &Index;
        reportTime(Argv[0], [&] { run(); });
      }
    }
    cl::ResetCommandLineParser(); // must do this before opts are destroyed.
  }
};

// FIXME(kbobyrev): Ideas for more commands:
// * load/swap/reload index: this would make it possible to get rid of llvm::cl
//   usages in the tool driver and actually use llvm::cl library in the REPL.
// * show posting list density histogram (our dump data somewhere so that user
//   could build one)
// * show number of tokens of each kind
// * print out tokens with the most dense posting lists
// * print out tokens with least dense posting lists

class FuzzyFind : public Command {
  cl::opt<std::string> Query{
      "query",
      cl::Positional,
      cl::Required,
      cl::desc("Query string to be fuzzy-matched"),
  };
  cl::opt<std::string> Scopes{
      "scopes",
      cl::desc("Allowed symbol scopes (comma-separated list)"),
  };
  cl::opt<unsigned> Limit{
      "limit",
      cl::init(10),
      cl::desc("Max results to display"),
  };

  void run() override {
    FuzzyFindRequest Request;
    Request.Limit = Limit;
    Request.Query = Query;
    if (Scopes.getNumOccurrences() > 0) {
      SmallVector<StringRef, 8> Scopes;
      StringRef(this->Scopes).split(Scopes, ',');
      Request.Scopes = {Scopes.begin(), Scopes.end()};
    }
    Request.AnyScope = Request.Scopes.empty();
    // FIXME(kbobyrev): Print symbol final scores to see the distribution.
    static const auto OutputFormat = "{0,-4} | {1,-40} | {2,-25}\n";
    outs() << formatv(OutputFormat, "Rank", "Symbol ID", "Symbol Name");
    size_t Rank = 0;
    Index->fuzzyFind(Request, [&](const Symbol &Sym) {
      outs() << formatv(OutputFormat, Rank++, Sym.ID.str(), Sym.Name);
    });
  }
};

class Lookup : public Command {
  cl::opt<std::string> ID{
      "id",
      cl::Positional,
      cl::desc("Symbol ID to look up (hex)"),
  };
  cl::opt<std::string> Name{
      "name", cl::desc("Qualified name to look up."),
  };

  void run() override {
    if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) {
      outs() << "Missing required argument: please provide id or -name.\n";
      return;
    }
    std::vector<SymbolID> IDs;
    if (ID.getNumOccurrences()) {
      auto SID = SymbolID::fromStr(ID);
      if (!SID) {
        outs() << toString(SID.takeError()) << "\n";
        return;
      }
      IDs.push_back(*SID);
    } else {
      IDs = getSymbolIDsFromIndex(Name, Index);
    }

    LookupRequest Request;
    Request.IDs.insert(IDs.begin(), IDs.end());
    bool FoundSymbol = false;
    Index->lookup(Request, [&](const Symbol &Sym) {
      FoundSymbol = true;
      outs() << toYAML(Sym);
    });
    if (!FoundSymbol)
      outs() << "not found\n";
  }
};

class Refs : public Command {
  cl::opt<std::string> ID{
      "id", cl::Positional,
      cl::desc("Symbol ID of the symbol being queried (hex)."),
  };
  cl::opt<std::string> Name{
      "name", cl::desc("Qualified name of the symbol being queried."),
  };
  cl::opt<std::string> Filter{
      "filter", cl::init(".*"),
      cl::desc(
          "Print all results from files matching this regular expression."),
  };

  void run() override {
    if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) {
      outs() << "Missing required argument: please provide id or -name.\n";
      return;
    }
    std::vector<SymbolID> IDs;
    if (ID.getNumOccurrences()) {
      auto SID = SymbolID::fromStr(ID);
      if (!SID) {
        outs() << toString(SID.takeError()) << "\n";
        return;
      }
      IDs.push_back(*SID);
    } else {
      IDs = getSymbolIDsFromIndex(Name, Index);
      if (IDs.size() > 1) {
        outs() << formatv("The name {0} is ambiguous, found {1} different "
                          "symbols. Please use id flag to disambiguate.\n",
                          Name, IDs.size());
        return;
      }
    }
    RefsRequest RefRequest;
    RefRequest.IDs.insert(IDs.begin(), IDs.end());
    Regex RegexFilter(Filter);
    Index->refs(RefRequest, [&RegexFilter](const Ref &R) {
      auto U = URI::parse(R.Location.FileURI);
      if (!U) {
        outs() << U.takeError();
        return;
      }
      if (RegexFilter.match(U->body()))
        outs() << R << "\n";
    });
  }
};

struct {
  const char *Name;
  const char *Description;
  std::function<std::unique_ptr<Command>()> Implementation;
} CommandInfo[] = {
    {"find", "Search for symbols with fuzzyFind", llvm::make_unique<FuzzyFind>},
    {"lookup", "Dump symbol details by ID or qualified name",
     llvm::make_unique<Lookup>},
    {"refs", "Find references by ID or qualified name",
     llvm::make_unique<Refs>},
};

std::unique_ptr<SymbolIndex> openIndex(StringRef Index) {
  return loadIndex(Index, /*UseDex=*/true);
}

} // namespace

int main(int argc, const char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, Overview);
  cl::ResetCommandLineParser(); // We reuse it for REPL commands.
  sys::PrintStackTraceOnErrorSignal(argv[0]);

  std::unique_ptr<SymbolIndex> Index;
  reportTime("Dex build", [&]() {
    Index = openIndex(IndexPath);
  });

  if (!Index) {
    outs() << "Failed to open the index.\n";
    return -1;
  }

  LineEditor LE("dexp");

  while (Optional<std::string> Request = LE.readLine()) {
    // Split on spaces and add required null-termination.
    std::replace(Request->begin(), Request->end(), ' ', '\0');
    SmallVector<StringRef, 8> Args;
    StringRef(*Request).split(Args, '\0', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
    if (Args.empty())
      continue;
    if (Args.front() == "help") {
      outs() << "dexp - Index explorer\nCommands:\n";
      for (const auto &C : CommandInfo)
        outs() << formatv("{0,16} - {1}\n", C.Name, C.Description);
      outs() << "Get detailed command help with e.g. `find -help`.\n";
      continue;
    }
    SmallVector<const char *, 8> FakeArgv;
    for (StringRef S : Args)
      FakeArgv.push_back(S.data()); // Terminated by separator or end of string.

    bool Recognized = false;
    for (const auto &Cmd : CommandInfo) {
      if (Cmd.Name == Args.front()) {
        Recognized = true;
        Cmd.Implementation()->parseAndRun(FakeArgv, Cmd.Description, *Index);
        break;
      }
    }
    if (!Recognized)
      outs() << "Unknown command. Try 'help'.\n";
  }

  return 0;
}
<commit_msg>[dexp] Change FuzzyFind to also print scope of symbols<commit_after>//===--- Dexp.cpp - Dex EXPloration tool ------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements a simple interactive tool which can be used to manually
// evaluate symbol search quality of Clangd index.
//
//===----------------------------------------------------------------------===//

#include "SourceCode.h"
#include "index/Serialization.h"
#include "index/dex/Dex.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/LineEditor/LineEditor.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Signals.h"

using namespace llvm;
using namespace clang;
using namespace clangd;

namespace {

cl::opt<std::string> IndexPath("index-path", cl::desc("Path to the index"),
                               cl::Positional, cl::Required);

static const std::string Overview = R"(
This is an **experimental** interactive tool to process user-provided search
queries over given symbol collection obtained via clangd-indexer. The
tool can be used to evaluate search quality of existing index implementations
and manually construct non-trivial test cases.

Type use "help" request to get information about the details.
)";

void reportTime(StringRef Name, function_ref<void()> F) {
  const auto TimerStart = std::chrono::high_resolution_clock::now();
  F();
  const auto TimerStop = std::chrono::high_resolution_clock::now();
  const auto Duration = std::chrono::duration_cast<std::chrono::milliseconds>(
      TimerStop - TimerStart);
  outs() << formatv("{0} took {1:ms+n}.\n", Name, Duration);
}

std::vector<SymbolID> getSymbolIDsFromIndex(StringRef QualifiedName,
                                            const SymbolIndex *Index) {
  FuzzyFindRequest Request;
  // Remove leading "::" qualifier as FuzzyFind doesn't need leading "::"
  // qualifier for global scope.
  bool IsGlobalScope = QualifiedName.consume_front("::");
  auto Names = splitQualifiedName(QualifiedName);
  if (IsGlobalScope || !Names.first.empty())
    Request.Scopes = {Names.first};
  else
    // QualifiedName refers to a symbol in global scope (e.g. "GlobalSymbol"),
    // add the global scope to the request.
    Request.Scopes = {""};

  Request.Query = Names.second;
  std::vector<SymbolID> SymIDs;
  Index->fuzzyFind(Request, [&](const Symbol &Sym) {
    std::string SymQualifiedName = (Sym.Scope + Sym.Name).str();
    if (QualifiedName == SymQualifiedName)
      SymIDs.push_back(Sym.ID);
  });
  return SymIDs;
}

// REPL commands inherit from Command and contain their options as members.
// Creating a Command populates parser options, parseAndRun() resets them.
class Command {
  // By resetting the parser options, we lost the standard -help flag.
  cl::opt<bool, false, cl::parser<bool>> Help{
      "help", cl::desc("Display available options"), cl::ValueDisallowed,
      cl::cat(cl::GeneralCategory)};
  virtual void run() = 0;

protected:
  const SymbolIndex *Index;

public:
  virtual ~Command() = default;
  virtual void parseAndRun(ArrayRef<const char *> Argv, const char *Overview,
                           const SymbolIndex &Index) {
    std::string ParseErrs;
    raw_string_ostream OS(ParseErrs);
    bool Ok =
        cl::ParseCommandLineOptions(Argv.size(), Argv.data(), Overview, &OS);
    if (Help.getNumOccurrences() > 0) {
      // Avoid printing parse errors in this case.
      // (Well, in theory. A bunch get printed to llvm::errs() regardless!)
      cl::PrintHelpMessage();
    } else {
      outs() << OS.str();
      if (Ok) {
        this->Index = &Index;
        reportTime(Argv[0], [&] { run(); });
      }
    }
    cl::ResetCommandLineParser(); // must do this before opts are destroyed.
  }
};

// FIXME(kbobyrev): Ideas for more commands:
// * load/swap/reload index: this would make it possible to get rid of llvm::cl
//   usages in the tool driver and actually use llvm::cl library in the REPL.
// * show posting list density histogram (our dump data somewhere so that user
//   could build one)
// * show number of tokens of each kind
// * print out tokens with the most dense posting lists
// * print out tokens with least dense posting lists

class FuzzyFind : public Command {
  cl::opt<std::string> Query{
      "query",
      cl::Positional,
      cl::Required,
      cl::desc("Query string to be fuzzy-matched"),
  };
  cl::opt<std::string> Scopes{
      "scopes",
      cl::desc("Allowed symbol scopes (comma-separated list)"),
  };
  cl::opt<unsigned> Limit{
      "limit",
      cl::init(10),
      cl::desc("Max results to display"),
  };

  void run() override {
    FuzzyFindRequest Request;
    Request.Limit = Limit;
    Request.Query = Query;
    if (Scopes.getNumOccurrences() > 0) {
      SmallVector<StringRef, 8> Scopes;
      StringRef(this->Scopes).split(Scopes, ',');
      Request.Scopes = {Scopes.begin(), Scopes.end()};
    }
    Request.AnyScope = Request.Scopes.empty();
    // FIXME(kbobyrev): Print symbol final scores to see the distribution.
    static const auto OutputFormat = "{0,-4} | {1,-40} | {2,-25}\n";
    outs() << formatv(OutputFormat, "Rank", "Symbol ID", "Symbol Name");
    size_t Rank = 0;
    Index->fuzzyFind(Request, [&](const Symbol &Sym) {
      outs() << formatv(OutputFormat, Rank++, Sym.ID.str(),
                        Sym.Scope + Sym.Name);
    });
  }
};

class Lookup : public Command {
  cl::opt<std::string> ID{
      "id",
      cl::Positional,
      cl::desc("Symbol ID to look up (hex)"),
  };
  cl::opt<std::string> Name{
      "name", cl::desc("Qualified name to look up."),
  };

  void run() override {
    if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) {
      outs() << "Missing required argument: please provide id or -name.\n";
      return;
    }
    std::vector<SymbolID> IDs;
    if (ID.getNumOccurrences()) {
      auto SID = SymbolID::fromStr(ID);
      if (!SID) {
        outs() << toString(SID.takeError()) << "\n";
        return;
      }
      IDs.push_back(*SID);
    } else {
      IDs = getSymbolIDsFromIndex(Name, Index);
    }

    LookupRequest Request;
    Request.IDs.insert(IDs.begin(), IDs.end());
    bool FoundSymbol = false;
    Index->lookup(Request, [&](const Symbol &Sym) {
      FoundSymbol = true;
      outs() << toYAML(Sym);
    });
    if (!FoundSymbol)
      outs() << "not found\n";
  }
};

class Refs : public Command {
  cl::opt<std::string> ID{
      "id", cl::Positional,
      cl::desc("Symbol ID of the symbol being queried (hex)."),
  };
  cl::opt<std::string> Name{
      "name", cl::desc("Qualified name of the symbol being queried."),
  };
  cl::opt<std::string> Filter{
      "filter", cl::init(".*"),
      cl::desc(
          "Print all results from files matching this regular expression."),
  };

  void run() override {
    if (ID.getNumOccurrences() == 0 && Name.getNumOccurrences() == 0) {
      outs() << "Missing required argument: please provide id or -name.\n";
      return;
    }
    std::vector<SymbolID> IDs;
    if (ID.getNumOccurrences()) {
      auto SID = SymbolID::fromStr(ID);
      if (!SID) {
        outs() << toString(SID.takeError()) << "\n";
        return;
      }
      IDs.push_back(*SID);
    } else {
      IDs = getSymbolIDsFromIndex(Name, Index);
      if (IDs.size() > 1) {
        outs() << formatv("The name {0} is ambiguous, found {1} different "
                          "symbols. Please use id flag to disambiguate.\n",
                          Name, IDs.size());
        return;
      }
    }
    RefsRequest RefRequest;
    RefRequest.IDs.insert(IDs.begin(), IDs.end());
    Regex RegexFilter(Filter);
    Index->refs(RefRequest, [&RegexFilter](const Ref &R) {
      auto U = URI::parse(R.Location.FileURI);
      if (!U) {
        outs() << U.takeError();
        return;
      }
      if (RegexFilter.match(U->body()))
        outs() << R << "\n";
    });
  }
};

struct {
  const char *Name;
  const char *Description;
  std::function<std::unique_ptr<Command>()> Implementation;
} CommandInfo[] = {
    {"find", "Search for symbols with fuzzyFind", llvm::make_unique<FuzzyFind>},
    {"lookup", "Dump symbol details by ID or qualified name",
     llvm::make_unique<Lookup>},
    {"refs", "Find references by ID or qualified name",
     llvm::make_unique<Refs>},
};

std::unique_ptr<SymbolIndex> openIndex(StringRef Index) {
  return loadIndex(Index, /*UseDex=*/true);
}

} // namespace

int main(int argc, const char *argv[]) {
  cl::ParseCommandLineOptions(argc, argv, Overview);
  cl::ResetCommandLineParser(); // We reuse it for REPL commands.
  sys::PrintStackTraceOnErrorSignal(argv[0]);

  std::unique_ptr<SymbolIndex> Index;
  reportTime("Dex build", [&]() {
    Index = openIndex(IndexPath);
  });

  if (!Index) {
    outs() << "Failed to open the index.\n";
    return -1;
  }

  LineEditor LE("dexp");

  while (Optional<std::string> Request = LE.readLine()) {
    // Split on spaces and add required null-termination.
    std::replace(Request->begin(), Request->end(), ' ', '\0');
    SmallVector<StringRef, 8> Args;
    StringRef(*Request).split(Args, '\0', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
    if (Args.empty())
      continue;
    if (Args.front() == "help") {
      outs() << "dexp - Index explorer\nCommands:\n";
      for (const auto &C : CommandInfo)
        outs() << formatv("{0,16} - {1}\n", C.Name, C.Description);
      outs() << "Get detailed command help with e.g. `find -help`.\n";
      continue;
    }
    SmallVector<const char *, 8> FakeArgv;
    for (StringRef S : Args)
      FakeArgv.push_back(S.data()); // Terminated by separator or end of string.

    bool Recognized = false;
    for (const auto &Cmd : CommandInfo) {
      if (Cmd.Name == Args.front()) {
        Recognized = true;
        Cmd.Implementation()->parseAndRun(FakeArgv, Cmd.Description, *Index);
        break;
      }
    }
    if (!Recognized)
      outs() << "Unknown command. Try 'help'.\n";
  }

  return 0;
}
<|endoftext|>


<commit_before>#include "gtest/gtest.h"
#include "LinAlg/Vector.hpp"
#include "LinAlg/VectorView.hpp"
#include "LinAlg/DiagonalMatrix.hpp"
#include "LinAlg/Matrix.hpp"
#include "LinAlg/Selector.hpp"
#include "distributions.hpp"
#include "cpputil/math_utils.hpp"
#include "test_utils/test_utils.hpp"
#include <fstream>

namespace {
  using namespace BOOM;
  using std::endl;
  using std::cout;

  class SelectorTest : public ::testing::Test {
   protected:
    SelectorTest() {
      GlobalRng::rng.seed(8675309);
    }
  };

  TEST_F(SelectorTest, Equality) {
    Selector s1("001");
    Selector s2("101");
    EXPECT_NE(s1, s2);
    EXPECT_TRUE(s1 != s2);
    EXPECT_FALSE(s1 == s2);

    s2.flip(0); // now 001
    EXPECT_EQ(s1, s2);
    EXPECT_TRUE(s1 == s2);
    EXPECT_FALSE(s1 != s2);

    s2.flip(0);
    swap(s1, s2);
    Selector s3("001");
    EXPECT_EQ(s2, s3);
    EXPECT_NE(s1, s3);
    s3.flip(0);
    EXPECT_EQ(s1, s3);
    EXPECT_NE(s2, s3);
  }

  TEST_F(SelectorTest, Indexing) {
    Selector s1("101001101");
    EXPECT_EQ(s1.nvars(), 5);
    EXPECT_EQ(s1.nvars_possible(), 9);
    EXPECT_EQ(s1.nvars_excluded(), 4);

    EXPECT_EQ(0, s1.indx(0));
    EXPECT_EQ(2, s1.indx(1));
    EXPECT_EQ(5, s1.indx(2));
    EXPECT_EQ(6, s1.indx(3));
    EXPECT_EQ(8, s1.indx(4));

    EXPECT_EQ(0, s1.INDX(0));
    EXPECT_EQ(1, s1.INDX(2));
    EXPECT_EQ(2, s1.INDX(5));
    EXPECT_EQ(3, s1.INDX(6));
    EXPECT_EQ(4, s1.INDX(8));
  }

  TEST_F(SelectorTest, Append) {
    Selector s1("010");
    EXPECT_EQ(s1.nvars(), 1);
    EXPECT_EQ(s1.nvars_possible(), 3);

    s1.push_back(true);
    EXPECT_EQ(s1.nvars(), 2);
    EXPECT_EQ(s1.nvars_possible(), 4);

    s1.push_back(false);
    EXPECT_EQ(s1.nvars(), 2);
    EXPECT_EQ(s1.nvars_possible(), 5);

    // Current state is "01010".
    // Set it to "0100"
    s1.erase(3);
    EXPECT_EQ(s1.nvars(), 1);
    EXPECT_EQ(s1.nvars_possible(), 4);
    EXPECT_TRUE(s1[1]);
  }

  TEST_F(SelectorTest, ToVectorTest) {
    Selector s("00010");
    Vector v = s.to_Vector();
    EXPECT_EQ(v.size(), 5);
    EXPECT_DOUBLE_EQ(v[0], 0);
    EXPECT_DOUBLE_EQ(v[1], 0);
    EXPECT_DOUBLE_EQ(v[2], 0);
    EXPECT_DOUBLE_EQ(v[3], 1);
    EXPECT_DOUBLE_EQ(v[4], 0);
  }

  TEST_F(SelectorTest, SelectRowsTest) {
    Matrix big(10, 4);
    big.randomize();

    Selector inc(10, false);
    inc.add(2);
    inc.add(7);

    Matrix small = inc.select_rows(big);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));

    big.randomize();
    ConstSubMatrix big_view(big);
    small = inc.select_rows(big_view);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));

    big.randomize();
    SubMatrix mutable_big_view(big);
    small = inc.select_rows(big_view);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));
  }

  TEST_F(SelectorTest, SparseSum) {
    Vector v(100);
    v.randomize();

    Selector inc(100);
    inc.drop_all();
    EXPECT_DOUBLE_EQ(0.0, inc.sparse_sum(v));

    inc.add(3);
    inc.add(17);
    inc.add(12);
    EXPECT_DOUBLE_EQ(
        inc.sparse_sum(v),
        v[3] + v[12] + v[17]);
  }

  // This test checks the Selector's ability to select from std::vector.
  TEST_F(SelectorTest, VectorInt) {
    std::vector<int> big = {1, 2, 3, 4, 5};
    Selector inc("10010");
    std::vector<int> small = inc.select(big);
    EXPECT_EQ(2, small.size());
    EXPECT_EQ(1, small[0]);
    EXPECT_EQ(4, small[1]);
  }

  TEST_F(SelectorTest, SelectorMatrixTest) {
    Selector inc_vec("111101");
    SelectorMatrix inc(3, 2, inc_vec);
    EXPECT_EQ(3, inc.nrow());
    EXPECT_EQ(2, inc.ncol());

    // Check that the input vector fills column-by-column.
    EXPECT_TRUE(inc(0, 0));
    EXPECT_TRUE(inc(1, 0));
    EXPECT_TRUE(inc(2, 0));
    EXPECT_TRUE(inc(0, 1));
    EXPECT_FALSE(inc(1, 1));
    EXPECT_TRUE(inc(2, 1));

    EXPECT_EQ(inc_vec, inc.vectorize());

    inc.drop(0, 1);
    EXPECT_FALSE(inc(0, 1));
    inc.add(0, 1);
    EXPECT_TRUE(inc(0, 1));
    inc.flip(0, 1);
    EXPECT_FALSE(inc(0, 1));
    inc.flip(0, 1);
    EXPECT_TRUE(inc(0, 1));

    EXPECT_FALSE(inc.all_in());
    EXPECT_FALSE(inc.all_out());
    inc.drop_all();
    for (int i = 0; i < inc.nrow(); ++i) {
      for (int j = 0; j < inc.ncol(); ++j) {
        EXPECT_FALSE(inc(i, j));
      }
    }
    EXPECT_TRUE(inc.all_out());

    inc.add_all();
    for (int i = 0; i < inc.nrow(); ++i) {
      for (int j = 0; j < inc.ncol(); ++j) {
        EXPECT_TRUE(inc(i, j));
      }
    }
    EXPECT_TRUE(inc.all_in());

    SelectorMatrix wide(4, 3, Selector("100000010010"));
    // 1 0 0
    // 0 0 0
    // 0 0 1
    // 0 1 0
    Selector any(wide.row_any());
    EXPECT_TRUE(any[0]);
    EXPECT_FALSE(any[1]);
    EXPECT_TRUE(any[2]);
    EXPECT_TRUE(any[3]);

    Selector all(wide.row_all());
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[3]);

    Selector row2 = wide.row(2);
    EXPECT_EQ(3, row2.nvars_possible());
    EXPECT_FALSE(row2[0]);
    EXPECT_FALSE(row2[1]);
    EXPECT_TRUE(row2[2]);

    Matrix selectable(4, 3);
    selectable.randomize();
    Vector selected = wide.vector_select(selectable);
    EXPECT_EQ(3, selected.size());
    EXPECT_DOUBLE_EQ(selected[0], selectable(0, 0));
    EXPECT_DOUBLE_EQ(selected[1], selectable(3, 1));
    EXPECT_DOUBLE_EQ(selected[2], selectable(2, 2));

    Matrix expanded(4, 3, 0.0);
    expanded(0, 0) = selectable(0, 0);
    expanded(3, 1) = selectable(3, 1);
    expanded(2, 2) = selectable(2, 2);

    wide.add(3, 0);
    wide.add(3, 2);
    all = wide.row_all();
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_TRUE(all[3]);
  }

  TEST_F(SelectorTest, DiagonalMatrixTest) {
    Selector empty(4, false);
    Selector full(4, true);
    Selector one(4, false);
    one.add(2);
    Selector three(4, true);
    three.drop(2);

    Vector v(4);
    v.randomize();
    DiagonalMatrix dmat(v);

    EXPECT_EQ(empty.select_square(dmat).nrow(), 0);
    EXPECT_EQ(empty.select_square(dmat).ncol(), 0);
    EXPECT_EQ(full.select_square(dmat).nrow(), 4);
    EXPECT_EQ(full.select_square(dmat).ncol(), 4);
    EXPECT_TRUE(VectorEquals(full.select_square(dmat).diag(), v));

    EXPECT_EQ(one.select_square(dmat).nrow(), 1);
    EXPECT_EQ(one.select_square(dmat).ncol(), 1);
    EXPECT_TRUE(VectorEquals( one.select_square(dmat).diag(), one.select(v)));

    EXPECT_EQ(three.select_square(dmat).nrow(), 3);
    EXPECT_EQ(three.select_square(dmat).ncol(), 3);
    EXPECT_TRUE(VectorEquals(three.select_square(dmat).diag(),
                             three.select(v)));
  }

  TEST_F(SelectorTest, FillMissingValues) {
    Vector x(5);
    x.randomize();

    Selector all(5, true);
    Selector none(5, false);

    EXPECT_TRUE(VectorEquals(x, all.fill_missing_elements(x, 3.0)));
    EXPECT_TRUE(VectorEquals(Vector(5, 3.0),
                             none.fill_missing_elements(x, 3.0)));

    x.randomize();
    Selector three("11010");
    Vector y = x;
    three.fill_missing_elements(x, 3.0);
    y[2] = 3.0;
    y[4] = 3.0;
    EXPECT_TRUE(VectorEquals(x, y));

    Vector values = {1.2, 2.4};
    three.fill_missing_elements(x, values);
    y[2] = 1.2;
    y[4] = 2.4;
    EXPECT_TRUE(VectorEquals(x, y));
  }

}  // namespace
<commit_msg>Add a test for Selector::complement.<commit_after>#include "gtest/gtest.h"
#include "LinAlg/Vector.hpp"
#include "LinAlg/VectorView.hpp"
#include "LinAlg/DiagonalMatrix.hpp"
#include "LinAlg/Matrix.hpp"
#include "LinAlg/Selector.hpp"
#include "distributions.hpp"
#include "cpputil/math_utils.hpp"
#include "test_utils/test_utils.hpp"
#include <fstream>

namespace {
  using namespace BOOM;
  using std::endl;
  using std::cout;

  class SelectorTest : public ::testing::Test {
   protected:
    SelectorTest() {
      GlobalRng::rng.seed(8675309);
    }
  };

  TEST_F(SelectorTest, Equality) {
    Selector s1("001");
    Selector s2("101");
    EXPECT_NE(s1, s2);
    EXPECT_TRUE(s1 != s2);
    EXPECT_FALSE(s1 == s2);

    s2.flip(0); // now 001
    EXPECT_EQ(s1, s2);
    EXPECT_TRUE(s1 == s2);
    EXPECT_FALSE(s1 != s2);

    s2.flip(0);
    swap(s1, s2);
    Selector s3("001");
    EXPECT_EQ(s2, s3);
    EXPECT_NE(s1, s3);
    s3.flip(0);
    EXPECT_EQ(s1, s3);
    EXPECT_NE(s2, s3);
  }

  TEST_F(SelectorTest, Complement) {
    Selector s1("101001101");
    Selector s2 = s1.complement();
    EXPECT_EQ(s2.nvars_possible(), s1.nvars_possible());
    for (int i = 0; i < s1.nvars_possible(); ++i) {
      EXPECT_EQ(s1[i], !s2[i]);
    }
  }

  TEST_F(SelectorTest, Indexing) {
    Selector s1("101001101");
    EXPECT_EQ(s1.nvars(), 5);
    EXPECT_EQ(s1.nvars_possible(), 9);
    EXPECT_EQ(s1.nvars_excluded(), 4);

    EXPECT_EQ(0, s1.indx(0));
    EXPECT_EQ(2, s1.indx(1));
    EXPECT_EQ(5, s1.indx(2));
    EXPECT_EQ(6, s1.indx(3));
    EXPECT_EQ(8, s1.indx(4));

    EXPECT_EQ(0, s1.INDX(0));
    EXPECT_EQ(1, s1.INDX(2));
    EXPECT_EQ(2, s1.INDX(5));
    EXPECT_EQ(3, s1.INDX(6));
    EXPECT_EQ(4, s1.INDX(8));
  }

  TEST_F(SelectorTest, Append) {
    Selector s1("010");
    EXPECT_EQ(s1.nvars(), 1);
    EXPECT_EQ(s1.nvars_possible(), 3);

    s1.push_back(true);
    EXPECT_EQ(s1.nvars(), 2);
    EXPECT_EQ(s1.nvars_possible(), 4);

    s1.push_back(false);
    EXPECT_EQ(s1.nvars(), 2);
    EXPECT_EQ(s1.nvars_possible(), 5);

    // Current state is "01010".
    // Set it to "0100"
    s1.erase(3);
    EXPECT_EQ(s1.nvars(), 1);
    EXPECT_EQ(s1.nvars_possible(), 4);
    EXPECT_TRUE(s1[1]);
  }

  TEST_F(SelectorTest, ToVectorTest) {
    Selector s("00010");
    Vector v = s.to_Vector();
    EXPECT_EQ(v.size(), 5);
    EXPECT_DOUBLE_EQ(v[0], 0);
    EXPECT_DOUBLE_EQ(v[1], 0);
    EXPECT_DOUBLE_EQ(v[2], 0);
    EXPECT_DOUBLE_EQ(v[3], 1);
    EXPECT_DOUBLE_EQ(v[4], 0);
  }

  TEST_F(SelectorTest, SelectRowsTest) {
    Matrix big(10, 4);
    big.randomize();

    Selector inc(10, false);
    inc.add(2);
    inc.add(7);

    Matrix small = inc.select_rows(big);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));

    big.randomize();
    ConstSubMatrix big_view(big);
    small = inc.select_rows(big_view);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));

    big.randomize();
    SubMatrix mutable_big_view(big);
    small = inc.select_rows(big_view);
    EXPECT_EQ(2, small.nrow());
    EXPECT_EQ(4, small.ncol());
    EXPECT_TRUE(VectorEquals(small.row(0), big.row(2)));
  }

  TEST_F(SelectorTest, SparseSum) {
    Vector v(100);
    v.randomize();

    Selector inc(100);
    inc.drop_all();
    EXPECT_DOUBLE_EQ(0.0, inc.sparse_sum(v));

    inc.add(3);
    inc.add(17);
    inc.add(12);
    EXPECT_DOUBLE_EQ(
        inc.sparse_sum(v),
        v[3] + v[12] + v[17]);
  }

  // This test checks the Selector's ability to select from std::vector.
  TEST_F(SelectorTest, VectorInt) {
    std::vector<int> big = {1, 2, 3, 4, 5};
    Selector inc("10010");
    std::vector<int> small = inc.select(big);
    EXPECT_EQ(2, small.size());
    EXPECT_EQ(1, small[0]);
    EXPECT_EQ(4, small[1]);
  }

  TEST_F(SelectorTest, SelectorMatrixTest) {
    Selector inc_vec("111101");
    SelectorMatrix inc(3, 2, inc_vec);
    EXPECT_EQ(3, inc.nrow());
    EXPECT_EQ(2, inc.ncol());

    // Check that the input vector fills column-by-column.
    EXPECT_TRUE(inc(0, 0));
    EXPECT_TRUE(inc(1, 0));
    EXPECT_TRUE(inc(2, 0));
    EXPECT_TRUE(inc(0, 1));
    EXPECT_FALSE(inc(1, 1));
    EXPECT_TRUE(inc(2, 1));

    EXPECT_EQ(inc_vec, inc.vectorize());

    inc.drop(0, 1);
    EXPECT_FALSE(inc(0, 1));
    inc.add(0, 1);
    EXPECT_TRUE(inc(0, 1));
    inc.flip(0, 1);
    EXPECT_FALSE(inc(0, 1));
    inc.flip(0, 1);
    EXPECT_TRUE(inc(0, 1));

    EXPECT_FALSE(inc.all_in());
    EXPECT_FALSE(inc.all_out());
    inc.drop_all();
    for (int i = 0; i < inc.nrow(); ++i) {
      for (int j = 0; j < inc.ncol(); ++j) {
        EXPECT_FALSE(inc(i, j));
      }
    }
    EXPECT_TRUE(inc.all_out());

    inc.add_all();
    for (int i = 0; i < inc.nrow(); ++i) {
      for (int j = 0; j < inc.ncol(); ++j) {
        EXPECT_TRUE(inc(i, j));
      }
    }
    EXPECT_TRUE(inc.all_in());

    SelectorMatrix wide(4, 3, Selector("100000010010"));
    // 1 0 0
    // 0 0 0
    // 0 0 1
    // 0 1 0
    Selector any(wide.row_any());
    EXPECT_TRUE(any[0]);
    EXPECT_FALSE(any[1]);
    EXPECT_TRUE(any[2]);
    EXPECT_TRUE(any[3]);

    Selector all(wide.row_all());
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[3]);

    Selector row2 = wide.row(2);
    EXPECT_EQ(3, row2.nvars_possible());
    EXPECT_FALSE(row2[0]);
    EXPECT_FALSE(row2[1]);
    EXPECT_TRUE(row2[2]);

    Matrix selectable(4, 3);
    selectable.randomize();
    Vector selected = wide.vector_select(selectable);
    EXPECT_EQ(3, selected.size());
    EXPECT_DOUBLE_EQ(selected[0], selectable(0, 0));
    EXPECT_DOUBLE_EQ(selected[1], selectable(3, 1));
    EXPECT_DOUBLE_EQ(selected[2], selectable(2, 2));

    Matrix expanded(4, 3, 0.0);
    expanded(0, 0) = selectable(0, 0);
    expanded(3, 1) = selectable(3, 1);
    expanded(2, 2) = selectable(2, 2);

    wide.add(3, 0);
    wide.add(3, 2);
    all = wide.row_all();
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_FALSE(all[0]);
    EXPECT_TRUE(all[3]);
  }

  TEST_F(SelectorTest, DiagonalMatrixTest) {
    Selector empty(4, false);
    Selector full(4, true);
    Selector one(4, false);
    one.add(2);
    Selector three(4, true);
    three.drop(2);

    Vector v(4);
    v.randomize();
    DiagonalMatrix dmat(v);

    EXPECT_EQ(empty.select_square(dmat).nrow(), 0);
    EXPECT_EQ(empty.select_square(dmat).ncol(), 0);
    EXPECT_EQ(full.select_square(dmat).nrow(), 4);
    EXPECT_EQ(full.select_square(dmat).ncol(), 4);
    EXPECT_TRUE(VectorEquals(full.select_square(dmat).diag(), v));

    EXPECT_EQ(one.select_square(dmat).nrow(), 1);
    EXPECT_EQ(one.select_square(dmat).ncol(), 1);
    EXPECT_TRUE(VectorEquals( one.select_square(dmat).diag(), one.select(v)));

    EXPECT_EQ(three.select_square(dmat).nrow(), 3);
    EXPECT_EQ(three.select_square(dmat).ncol(), 3);
    EXPECT_TRUE(VectorEquals(three.select_square(dmat).diag(),
                             three.select(v)));
  }

  TEST_F(SelectorTest, FillMissingValues) {
    Vector x(5);
    x.randomize();

    Selector all(5, true);
    Selector none(5, false);

    EXPECT_TRUE(VectorEquals(x, all.fill_missing_elements(x, 3.0)));
    EXPECT_TRUE(VectorEquals(Vector(5, 3.0),
                             none.fill_missing_elements(x, 3.0)));

    x.randomize();
    Selector three("11010");
    Vector y = x;
    three.fill_missing_elements(x, 3.0);
    y[2] = 3.0;
    y[4] = 3.0;
    EXPECT_TRUE(VectorEquals(x, y));

    Vector values = {1.2, 2.4};
    three.fill_missing_elements(x, values);
    y[2] = 1.2;
    y[4] = 2.4;
    EXPECT_TRUE(VectorEquals(x, y));
  }

}  // namespace
<|endoftext|>


<commit_before>//=====================================================================//
/*!	@file
	@brief	LCD ドットマトリックスの簡単なサンプル @n
			ST7565(R)、128 x 64 ピクセルの液晶を接続 @n
			/CS  ---> P53       (36) @n
			A0   ---> P50       (33) @n
			SD   ---> P13/SO20  (43) @n
			SCL  ---> P15/SCK20 (41) @n
			/RES ---> /RESET    ( 6)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "G13/system.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/itimer.hpp"
#include "common/format.hpp"
#include "common/delay.hpp"
#include "common/monograph.hpp"

// ターゲットＬＣＤのタイプを選択
// #define LCD_ST7565
#define LCD_SSD1306
#ifdef LCD_ST7565
#include "chip/ST7565.hpp"
#endif
#ifdef LCD_SSD1306
#include "chip/SSD1306.hpp"
#endif

namespace {
	// 送信、受信バッファの定義
	typedef utils::fifo<uint8_t, 32> buffer;
	// UART の定義（SAU02、SAU03）
	device::uart_io<device::SAU02, device::SAU03, buffer, buffer> uart_;

	device::itimer<uint8_t> itm_;

	// CSI(SPI) の定義、CSI20 の通信では、「SAU10」を利用、１ユニット、チャネル０
	typedef device::csi_io<device::SAU10> csi;
	csi csi_;

	// LCD インターフェースの定義
	typedef device::PORT<device::port_no::P5,  device::bitpos::B5> lcd_sel;	///< LCD 選択信号
	typedef device::PORT<device::port_no::P5,  device::bitpos::B0> lcd_reg;	///< LCD レジスタ選択

#ifdef LCD_ST7565
	chip::ST7565<csi, lcd_sel, lcd_reg> lcd_(csi_);
#endif
#ifdef LCD_SSD1306
	chip::SSD1306<csi, lcd_sel, lcd_reg> lcd_(csi_);
#endif

	graphics::monograph bitmap_;

	uint8_t v_ = 91;
	uint8_t m_ = 123;
	uint8_t rand_()
	{
		v_ += v_ << 2;
		++v_;
		uint8_t n = 0;
		if(m_ & 0x02) n = 1;
		if(m_ & 0x40) n ^= 1;
		m_ += m_;
		if(n == 0) ++m_;
		return v_ ^ m_;
	}
}

const void* ivec_[] __attribute__ ((section (".ivec"))) = {
	/*  0 */  nullptr,
	/*  1 */  nullptr,
	/*  2 */  nullptr,
	/*  3 */  nullptr,
	/*  4 */  nullptr,
	/*  5 */  nullptr,
	/*  6 */  nullptr,
	/*  7 */  nullptr,
	/*  8 */  nullptr,
	/*  9 */  nullptr,
	/* 10 */  nullptr,
	/* 11 */  nullptr,
	/* 12 */  nullptr,
	/* 13 */  nullptr,
	/* 14 */  nullptr,
	/* 15 */  nullptr,
	/* 16 */  reinterpret_cast<void*>(uart_.send_task),
	/* 17 */  reinterpret_cast<void*>(uart_.recv_task),
	/* 18 */  reinterpret_cast<void*>(uart_.error_task),
	/* 19 */  nullptr,
	/* 20 */  nullptr,
	/* 21 */  nullptr,
	/* 22 */  nullptr,
	/* 23 */  nullptr,
	/* 24 */  nullptr,
	/* 25 */  nullptr,
	/* 26 */  reinterpret_cast<void*>(itm_.task),
};

extern "C" {
	void sci_putch(char ch)
	{
		uart_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		uart_.puts(str);
	}
};

int main(int argc, char* argv[])
{
	using namespace device;

	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	// インターバル・タイマー開始
	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	// UART 開始
	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	// CSI 開始
	{
		uint8_t intr_level = 0;
		if(!csi_.start(8000000, csi::PHASE::TYPE4, intr_level)) {
			uart_.puts("CSI Start fail...\n");
		}
	}

	uart_.puts("Start RL78/G13 ST7565(R) sample\n");

	PM4.B3 = 0;  // output

	{
		lcd_.start(0x04);
		bitmap_.start();
		bitmap_.clear(0);
	}

	uint16_t x = rand_() & 127;
	uint16_t y = rand_() & 63;
	uint16_t xx;
	uint16_t yy;
	uint8_t loop = 0;
	uint8_t	nn = 0;

	uint8_t n = 0;
	while(1) {
		itm_.sync();

		if(nn >= 4) {
			lcd_.copy(bitmap_.fb());
			nn = 0;
		}
		++nn;

		if(loop >= 20) {
			loop = 0;
			bitmap_.clear(0);
			bitmap_.frame(0, 0, 128, 64, 1);
		}
		xx = rand_() & 127;
		yy = rand_() & 63;
		bitmap_.line(x, y, xx, yy, 1);
		x = xx;
		y = yy;
		++loop;

		++n;
		if(n >= 30) n = 0;
		P4.B3 = n < 10 ? false : true;
	}
}
<commit_msg>update LCD define<commit_after>//=====================================================================//
/*!	@file
	@brief	LCD ドットマトリックスの簡単なサンプル @n
			ST7565(R)、128 x 64 ピクセルの液晶を接続 @n
			/CS  ---> P53       (36) @n
			A0   ---> P50       (33) @n
			SD   ---> P13/SO20  (43) @n
			SCL  ---> P15/SCK20 (41) @n
			/RES ---> /RESET    ( 6)
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <cstdint>
#include "G13/system.hpp"
#include "common/port_utils.hpp"
#include "common/fifo.hpp"
#include "common/uart_io.hpp"
#include "common/itimer.hpp"
#include "common/format.hpp"
#include "common/delay.hpp"
#include "common/monograph.hpp"

// ターゲットＬＣＤのタイプを選択
#define LCD_ST7565
// #define LCD_SSD1306
#ifdef LCD_ST7565
#include "chip/ST7565.hpp"
#endif
#ifdef LCD_SSD1306
#include "chip/SSD1306.hpp"
#endif

namespace {
	// 送信、受信バッファの定義
	typedef utils::fifo<uint8_t, 32> buffer;
	// UART の定義（SAU02、SAU03）
	device::uart_io<device::SAU02, device::SAU03, buffer, buffer> uart_;

	device::itimer<uint8_t> itm_;

	// CSI(SPI) の定義、CSI20 の通信では、「SAU10」を利用、１ユニット、チャネル０
	typedef device::csi_io<device::SAU10> csi;
	csi csi_;

	// LCD インターフェースの定義
	typedef device::PORT<device::port_no::P5,  device::bitpos::B5> lcd_sel;	///< LCD 選択信号
	typedef device::PORT<device::port_no::P5,  device::bitpos::B0> lcd_reg;	///< LCD レジスタ選択

#ifdef LCD_ST7565
	chip::ST7565<csi, lcd_sel, lcd_reg> lcd_(csi_);
#endif
#ifdef LCD_SSD1306
	chip::SSD1306<csi, lcd_sel, lcd_reg> lcd_(csi_);
#endif

	graphics::monograph bitmap_;

	uint8_t v_ = 91;
	uint8_t m_ = 123;
	uint8_t rand_()
	{
		v_ += v_ << 2;
		++v_;
		uint8_t n = 0;
		if(m_ & 0x02) n = 1;
		if(m_ & 0x40) n ^= 1;
		m_ += m_;
		if(n == 0) ++m_;
		return v_ ^ m_;
	}
}

const void* ivec_[] __attribute__ ((section (".ivec"))) = {
	/*  0 */  nullptr,
	/*  1 */  nullptr,
	/*  2 */  nullptr,
	/*  3 */  nullptr,
	/*  4 */  nullptr,
	/*  5 */  nullptr,
	/*  6 */  nullptr,
	/*  7 */  nullptr,
	/*  8 */  nullptr,
	/*  9 */  nullptr,
	/* 10 */  nullptr,
	/* 11 */  nullptr,
	/* 12 */  nullptr,
	/* 13 */  nullptr,
	/* 14 */  nullptr,
	/* 15 */  nullptr,
	/* 16 */  reinterpret_cast<void*>(uart_.send_task),
	/* 17 */  reinterpret_cast<void*>(uart_.recv_task),
	/* 18 */  reinterpret_cast<void*>(uart_.error_task),
	/* 19 */  nullptr,
	/* 20 */  nullptr,
	/* 21 */  nullptr,
	/* 22 */  nullptr,
	/* 23 */  nullptr,
	/* 24 */  nullptr,
	/* 25 */  nullptr,
	/* 26 */  reinterpret_cast<void*>(itm_.task),
};

extern "C" {
	void sci_putch(char ch)
	{
		uart_.putch(ch);
	}

	void sci_puts(const char* str)
	{
		uart_.puts(str);
	}
};

int main(int argc, char* argv[])
{
	using namespace device;

	utils::port::pullup_all();  ///< 安全の為、全ての入力をプルアップ

	// インターバル・タイマー開始
	{
		uint8_t intr_level = 1;
		itm_.start(60, intr_level);
	}

	// UART 開始
	{
		uint8_t intr_level = 1;
		uart_.start(115200, intr_level);
	}

	// CSI 開始
	{
		uint8_t intr_level = 0;
		if(!csi_.start(8000000, csi::PHASE::TYPE4, intr_level)) {
			uart_.puts("CSI Start fail...\n");
		}
	}

	uart_.puts("Start RL78/G13 ST7565(R) sample\n");

	PM4.B3 = 0;  // output

	{
		lcd_.start(0x04);
		bitmap_.start();
		bitmap_.clear(0);
	}

	uint16_t x = rand_() & 127;
	uint16_t y = rand_() & 63;
	uint16_t xx;
	uint16_t yy;
	uint8_t loop = 0;
	uint8_t	nn = 0;

	uint8_t n = 0;
	while(1) {
		itm_.sync();

		if(nn >= 4) {
			lcd_.copy(bitmap_.fb());
			nn = 0;
		}
		++nn;

		if(loop >= 20) {
			loop = 0;
			bitmap_.clear(0);
			bitmap_.frame(0, 0, 128, 64, 1);
		}
		xx = rand_() & 127;
		yy = rand_() & 63;
		bitmap_.line(x, y, xx, yy, 1);
		x = xx;
		y = yy;
		++loop;

		++n;
		if(n >= 30) n = 0;
		P4.B3 = n < 10 ? false : true;
	}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2014 Kevin Brightwell <kevin.brightwell2@gmail.com>
 *
 * 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.
 */

#include "router/QWebRouter.h"

#include "router/QWebRoute.h"
#include "router/QWebRequest.h"
#include "router/QWebResponse.h"

#include <QDebug>
#include <QSharedPointer>

#include <QHttpServer/qhttpresponse.h>
#include <QHttpServer/qhttprequest.h>

const QString QWebRouter::DEFAULT_404_MSG =
    " "
    ""
    "   <title>404 Unknown Page</title>"
    ""
    ""
    "
404 Page Not Found
"
    "
Requested:
${page}

"
    ""
    "\n\n";

const QRegExp QWebRouter::DEFAULT_404_PATH_REPL("\\$\\{page\\}");

const QWebRouter::RouteFunction QWebRouter::DEFAULT_404 = [](QSharedPointer<QWebRequest> req,
                                                             QSharedPointer<QWebResponse> resp) {
        QString msg = QWebRouter::DEFAULT_404_MSG;
        resp->setStatusCode(QWebResponse::StatusCode::STATUS_NOT_FOUND);
        resp->writeText(msg.replace(QWebRouter::DEFAULT_404_PATH_REPL,
                                            req->path()), "text/html");
    };

QWebRouter::QWebRouter(const QHash<QWebService::HttpMethod, RoutePairList> routes,
                         const RouteFunction fourohfour,
                         QObject* parent)
    : QObject(parent),
    m_routes(routes),
    m_404(fourohfour) {

}

QWebRouter::~QWebRouter()
{

}

inline
void parsePOSTVars(QString query, QHash<QString, QString> &out) {
    const QStringList pairs = query.split('&', QString::SkipEmptyParts);

    for (QString pair : pairs) {
        const QStringList keyVals = pair.split('=', QString::KeepEmptyParts);

        out[keyVals[0]] = keyVals[1];
    }
}

void QWebRouter::handleRoute(QHttpRequest* request, QHttpResponse* resp)
{
    qDebug() << request->methodString() << ":" << request->url();

    const QString route = request->path();
    request->storeBody();

    QHash<QString, QString> postParams;
    if (request->url().hasQuery()) {
        parsePOSTVars(request->url().query(), postParams);
    }

    if (request->method() == QWebService::HttpMethod::HTTP_POST) {
        QString bodyVals = QString(request->body());

        parsePOSTVars(bodyVals, postParams);
    }

    // we recieved a request:
    QWebRoute::ParsedRoute::Ptr routeResponse;
    QWebRouter::RouteFunction func;

    QWebService::HttpMethod method = request->method();
    RoutePairList routes = m_routes[method];

    // search for the first matching path
    for (RoutePair pair : routes) {
        QSharedPointer<QWebRoute::ParsedRoute> resp = pair.first->checkPath(route);
        if (resp) {
            func = pair.second;
            routeResponse = resp;

            break;
        }
    }

    QSharedPointer<QWebRequest> reqPtr;

    if (routeResponse) {
        reqPtr = QWebRequest::create(request, postParams,
                                     routeResponse->urlParams(),
                                     routeResponse->splat());
    } else {
        reqPtr = QWebRequest::create(request, postParams, QHash<QString, QString>(), QStringList());
    }

    QSharedPointer<QWebResponse> webRespPtr = QWebResponse::create();

    connect(webRespPtr.data(), &QWebResponse::responseDataPrepared,
            m_service->getMiddleWareRegistrar(), &QWebMiddleWareRegistrar::webResponseDataPrepared);

    connect(request, &QHttpRequest::end, [this, func, reqPtr, resp, webRespPtr]() {
        if (func) {
            // we found a proper route:
            func(reqPtr, webRespPtr);
        } else {
            // 404:
            m_404(reqPtr, webRespPtr);
        }

        webRespPtr->writeToResponse(reqPtr, resp);
    });
}

<commit_msg>Fixed one segfault (line 108).  Test case now triggers the other.  See #10.<commit_after>/*
 * Copyright 2014 Kevin Brightwell <kevin.brightwell2@gmail.com>
 *
 * 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.
 */

#include "router/QWebRouter.h"

#include "router/QWebRoute.h"
#include "router/QWebRequest.h"
#include "router/QWebResponse.h"

#include <QDebug>
#include <QSharedPointer>

#include <QHttpServer/qhttpresponse.h>
#include <QHttpServer/qhttprequest.h>

const QString QWebRouter::DEFAULT_404_MSG =
    " "
    ""
    "   <title>404 Unknown Page</title>"
    ""
    ""
    "
404 Page Not Found
"
    "
Requested:
${page}

"
    ""
    "\n\n";

const QRegExp QWebRouter::DEFAULT_404_PATH_REPL("\\$\\{page\\}");

const QWebRouter::RouteFunction QWebRouter::DEFAULT_404 = [](QSharedPointer<QWebRequest> req,
                                                             QSharedPointer<QWebResponse> resp) {
        QString msg = QWebRouter::DEFAULT_404_MSG;
        resp->setStatusCode(QWebResponse::StatusCode::STATUS_NOT_FOUND);
        resp->writeText(msg.replace(QWebRouter::DEFAULT_404_PATH_REPL,
                                            req->path()), "text/html");
    };

QWebRouter::QWebRouter(const QHash<QWebService::HttpMethod, RoutePairList> routes,
                         const RouteFunction fourohfour,
                         QObject* parent)
    : QObject(parent),
    m_routes(routes),
    m_404(fourohfour) {

}

QWebRouter::~QWebRouter()
{

}

inline
void parsePOSTVars(QString query, QHash<QString, QString> &out) {
    const QStringList pairs = query.split('&', QString::SkipEmptyParts);

    for (QString pair : pairs) {
        const QStringList keyVals = pair.split('=', QString::KeepEmptyParts);

        out[keyVals[0]] = keyVals[1];
    }
}

void QWebRouter::handleRoute(QHttpRequest* request, QHttpResponse* resp)
{
    qDebug() << request->methodString() << ":" << request->url();

    const QString route = request->path();
    request->storeBody();

    QHash<QString, QString> postParams;
    if (request->url().hasQuery()) {
        parsePOSTVars(request->url().query(), postParams);
    }

    if (request->method() == QWebService::HttpMethod::HTTP_POST) {
        QString bodyVals = QString(request->body());

        parsePOSTVars(bodyVals, postParams);
    }

    // we recieved a request:
    QWebRoute::ParsedRoute::Ptr routeResponse;
    QWebRouter::RouteFunction func;

    QWebService::HttpMethod method = request->method();
    RoutePairList routes = m_routes[method];

    // search for the first matching path
    for (RoutePair pair : routes) {
        if(pair.first) {
            QSharedPointer<QWebRoute::ParsedRoute> resp = pair.first->checkPath(route);
            if (resp) {
                func = pair.second;
                routeResponse = resp;

                break;
            }
        }
    }

    QSharedPointer<QWebRequest> reqPtr;

    if (routeResponse) {
        reqPtr = QWebRequest::create(request, postParams,
                                     routeResponse->urlParams(),
                                     routeResponse->splat());
    } else {
        reqPtr = QWebRequest::create(request, postParams, QHash<QString, QString>(), QStringList());
    }

    QSharedPointer<QWebResponse> webRespPtr = QWebResponse::create();

    connect(webRespPtr.data(), &QWebResponse::responseDataPrepared,
            m_service->getMiddleWareRegistrar(), &QWebMiddleWareRegistrar::webResponseDataPrepared);

    connect(request, &QHttpRequest::end, [this, func, reqPtr, resp, webRespPtr]() {
        if (func) {
            // we found a proper route:
            func(reqPtr, webRespPtr);
        } else {
            // 404:
            m_404(reqPtr, webRespPtr);
        }

        webRespPtr->writeToResponse(reqPtr, resp);
    });
}

<|endoftext|>


<commit_before>#ifndef LIA_TRANSFORMS_LIST_COMP_HPP
#define LIA_TRANSFORMS_LIST_COMP_HPP

// Includes
#include "../detail/iterator.hpp"
#include "../detail/type_traits.hpp"
#include <algorithm>

namespace lia {
template<class Cont, typename Map>
inline auto map(const Cont& cont, Map&& mapped) -> Rebind<Cont, ResultOf<Unqualified<Map>>> {
    Rebind<Cont, ResultOf<Unqualified<Map>>> result;
    std::transform(std::begin(cont),std::end(cont), std::back_inserter(result),mapped);
    return result;
}

template<class Cont>
inline Unqualified<Cont> reverse(Cont&& cont) {
    Unqualified<Cont> result;
    std::reverse_copy(std::begin(cont),std::end(cont),std::back_inserter(result));
    return result;
}

template<class Cont>
inline Unqualified<Cont> intersperse(const Cont& cont, ValueType<Unqualified<Cont>> elem) {
    Unqualified<Cont> result;
    auto first = std::begin(cont);
    auto last = std::end(cont);
    if(first != last)
        result.push_back(*first++);
    while(first != last) {
        result.push_back(elem);
        result.push_back(*first++);
    }
    return result;
}

template<class Cont>
inline auto subsequences(const Cont& cont) -> Rebind<Cont, Unqualified<Cont>> {
    Rebind<Cont, Unqualified<Cont>> result;
    auto first = std::begin(cont);
    Unqualified<Cont> temp;
    auto max = 1ULL << cont.size();
    for(unsigned i = 0; i < max; ++i) {
        for(unsigned j = 0, h = i; h; h >>= 1, ++j) {
            if(h & 1)
                temp.push_back(*(first + j));
        }
        result.push_back(temp);
        temp.clear();
    }
    return result;
}

template<class Cont>
inline auto permutations(Cont&& cont) -> Rebind<Unqualified<Cont>, Unqualified<Cont>> {
    Rebind<Unqualified<Cont>, Unqualified<Cont>> result;
    Unqualified<Cont> temp(std::forward<Cont>(cont));
    do {
        result.push_back(temp);
    }
    while(std::next_permutation(std::begin(temp), std::end(temp)));
    return result;
}
} // lia

#endif // LIA_TRANSFORMS_LIST_COMP_HPP<commit_msg>Universal reference to pass-by-value<commit_after>#ifndef LIA_TRANSFORMS_LIST_COMP_HPP
#define LIA_TRANSFORMS_LIST_COMP_HPP

// Includes
#include "../detail/iterator.hpp"
#include "../detail/type_traits.hpp"
#include <algorithm>

namespace lia {
template<class Cont, typename Map>
inline auto map(const Cont& cont, Map&& mapped) -> Rebind<Cont, ResultOf<Unqualified<Map>>> {
    Rebind<Cont, ResultOf<Unqualified<Map>>> result;
    std::transform(std::begin(cont),std::end(cont), std::back_inserter(result),mapped);
    return result;
}

template<class Cont>
inline Unqualified<Cont> reverse(Cont&& cont) {
    Unqualified<Cont> result;
    std::reverse_copy(std::begin(cont), std::end(cont), std::back_inserter(result));
    return result;
}

template<class Cont>
inline Unqualified<Cont> intersperse(const Cont& cont, ValueType<Unqualified<Cont>> elem) {
    Unqualified<Cont> result;
    auto first = std::begin(cont);
    auto last = std::end(cont);
    if(first != last)
        result.push_back(*first++);
    while(first != last) {
        result.push_back(elem);
        result.push_back(*first++);
    }
    return result;
}

template<class Cont>
inline auto subsequences(const Cont& cont) -> Rebind<Cont, Unqualified<Cont>> {
    Rebind<Cont, Unqualified<Cont>> result;
    auto first = std::begin(cont);
    Unqualified<Cont> temp;
    auto max = 1ULL << cont.size();
    for(unsigned i = 0; i < max; ++i) {
        for(unsigned j = 0, h = i; h; h >>= 1, ++j) {
            if(h & 1)
                temp.push_back(*(first + j));
        }
        result.push_back(temp);
        temp.clear();
    }
    return result;
}

template<class Cont>
inline auto permutations(Cont cont) -> Rebind<Unqualified<Cont>, Unqualified<Cont>> {
    Rebind<Unqualified<Cont>, Unqualified<Cont>> result;
    do {
        result.push_back(cont);
    }
    while(std::next_permutation(std::begin(cont), std::end(cont)));
    return result;
}
} // lia

#endif // LIA_TRANSFORMS_LIST_COMP_HPP<|endoftext|>


<commit_before>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#ifdef BUILDING_WITH_MPI
#include <mpi.h>
#endif

#include "ProcessManager.hpp"
#include <QDataStream>

////////////////////////////////////////////////////////////////////

namespace
{
    void createDisplacedDoubleBlocks(int blocklength, const std::vector<int>& displacements, MPI_Datatype* newtypeP,
                                     int extent = -1)
    {
        int count = displacements.size();

        // Multiply the displacements by the block length
        std::vector<int> multiplied_disp;
        multiplied_disp.reserve(count);
        for(auto i: displacements) multiplied_disp.push_back(blocklength*i);

        // Create a datatype representing a structure of displaced blocks of the same size;
        MPI_Datatype indexedBlock;
        MPI_Type_create_indexed_block(count, blocklength, &multiplied_disp[0], MPI_DOUBLE, &indexedBlock);

        // Pad this datatype to modify the extent to the requested value
        MPI_Aint lb;
        MPI_Aint ex;
        MPI_Type_get_extent(indexedBlock, &lb, &ex);

        if (extent != -1)
        {
            MPI_Type_create_resized(indexedBlock, lb, extent*sizeof(double), newtypeP);
            // Commit the final type and free the intermediary one
            MPI_Type_commit(newtypeP);
            MPI_Type_free(&indexedBlock);
        }
        else
        {
            // No padding, just store the indexed block
            *newtypeP = indexedBlock;
            MPI_Type_commit(newtypeP);
        }
    }
}

std::atomic<int> ProcessManager::requests(0);

//////////////////////////////////////////////////////////////////////

void ProcessManager::initialize(int *argc, char ***argv)
{
#ifdef BUILDING_WITH_MPI
    int initialized;
    MPI_Initialized(&initialized);
    if (!initialized)
    {
        MPI_Init(argc, argv);
    }
#else
    Q_UNUSED(argc) Q_UNUSED(argv)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::finalize()
{
#ifdef BUILDING_WITH_MPI
    MPI_Finalize();
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::acquireMPI(int& rank, int& Nprocs)
{
#ifdef BUILDING_WITH_MPI
    int oldrequests = requests++;

    if (oldrequests) // if requests >=1
    {
        Nprocs = 1;
        rank = 0;
    }
    else // requests == 0
    {
        MPI_Comm_size(MPI_COMM_WORLD, &Nprocs);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    }
#else
    rank = 0;
    Nprocs = 1;
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::releaseMPI()
{
#ifdef BUILDING_WITH_MPI
    requests--;
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::barrier()
{
#ifdef BUILDING_WITH_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sendByteBuffer(QByteArray& buffer, int receiver, int tag)
{
#ifdef BUILDING_WITH_MPI
    MPI_Send(buffer.data(), buffer.size(), MPI_BYTE, receiver, tag, MPI_COMM_WORLD);
#else
    Q_UNUSED(buffer) Q_UNUSED(receiver) Q_UNUSED(tag)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::receiveByteBuffer(QByteArray& buffer, int& sender)
{
#ifdef BUILDING_WITH_MPI
    MPI_Status status;
    MPI_Recv(buffer.data(), buffer.size(), MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    sender = status.MPI_SOURCE;
#else
    Q_UNUSED(buffer) Q_UNUSED(sender)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::receiveByteBuffer(QByteArray &buffer, int sender, int& tag)
{
#ifdef BUILDING_WITH_MPI
    MPI_Status status;
    MPI_Recv(buffer.data(), buffer.size(), MPI_BYTE, sender, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    tag = status.MPI_TAG;
#else
    Q_UNUSED(buffer) Q_UNUSED(sender) Q_UNUSED(tag)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::gatherw(double* sendBuffer, int sendCount,
                             double* recvBuffer, int recvRank, int recvLength,
                             const std::vector<std::vector<int>>& recvDisplacements)
{
#ifdef BUILDING_WITH_MPI
    int size;
    int rank;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    // parameters for the senders
    std::vector<int> sendcnts(size, 0);                     // every process sends nothing to all processes
    sendcnts[recvRank] = sendCount;                         // except to the receiver
    std::vector<int> sdispls(size, 0);                      // starting from sendBuffer + 0
    std::vector<MPI_Datatype> sendtypes(size, MPI_DOUBLE);  // all doubles

    // parameters on the receiving end
    std::vector<int> recvcnts;
    if (rank != recvRank) recvcnts.resize(size, 0); // I am not receiver: receive nothing from every process
    else recvcnts.resize(size, 1);                  // I am receiver: receive 1 from every process
    std::vector<int> rdispls(size, 0);              // displacements will be contained in the datatypes
    std::vector<MPI_Datatype> recvtypes;            // we will construct derived datatypes for receiving from each process
    recvtypes.reserve(size);

    for (int r=0; r<size; r++)
    {
        MPI_Datatype newtype;
        createDisplacedDoubleBlocks(recvLength, recvDisplacements[r], &newtype);
        recvtypes.push_back(newtype);
    }

    MPI_Alltoallw(sendBuffer, &sendcnts[0], &sdispls[0], &sendtypes[0],
                  recvBuffer, &recvcnts[0], &rdispls[0], &recvtypes[0],
                  MPI_COMM_WORLD);

    for (int rank=0; rank<size; rank++) MPI_Type_free(&recvtypes[rank]);
#else
    Q_UNUSED(sendBuffer) Q_UNUSED(sendCount) Q_UNUSED(recvBuffer) Q_UNUSED(recvRank) Q_UNUSED(recvDisplacements)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::displacedBlocksAllToAll(double* sendBuffer, int sendCount,
                                             const std::vector<std::vector<int>>& sendDisplacements, int sendLength,
                                             int sendExtent, double* recvBuffer, int recvCount,
                                             const std::vector<std::vector<int>>& recvDisplacements, int recvLength,
                                             int recvExtent)
{
#ifdef BUILDING_WITH_MPI
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    std::vector<int> sendcnts(size,sendCount);
    std::vector<int> sdispls(size, 0);
    std::vector<MPI_Datatype> sendtypes;
    sendtypes.reserve(size);

    std::vector<int> recvcnts(size, recvCount);
    std::vector<int> rdispls(size, 0);
    std::vector<MPI_Datatype> recvtypes;
    recvtypes.reserve(size);

    for (int r=0; r<size; r++)
    {
        MPI_Datatype newtype;
        createDisplacedDoubleBlocks(sendLength, sendDisplacements[r], &newtype, sendExtent);
        sendtypes.push_back(newtype);

        createDisplacedDoubleBlocks(recvLength, recvDisplacements[r], &newtype, recvExtent);
        recvtypes.push_back(newtype);
    }

    MPI_Alltoallw(sendBuffer, &sendcnts[0], &sdispls[0], &sendtypes[0],
                  recvBuffer, &recvcnts[0], &rdispls[0], &recvtypes[0],
                  MPI_COMM_WORLD);

    for (int r=0; r<size; r++)
    {
        MPI_Type_free(&sendtypes[r]);
        MPI_Type_free(&recvtypes[r]);
    }
#else
    Q_UNUSED(sendBuffer) Q_UNUSED(sendCount) Q_UNUSED(sendDisplacements) Q_UNUSED(sendLength)
    Q_UNUSED(recvBuffer) Q_UNUSED(recvCount) Q_UNUSED(recvDisplacements) Q_UNUSED(recvLength)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sum(double* my_array, double* result_array, int nvalues, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Reduce(my_array, result_array, nvalues, MPI_DOUBLE, MPI_SUM, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(result_array) Q_UNUSED(nvalues) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sum_all(double* my_array, int nvalues)
{
#ifdef BUILDING_WITH_MPI
    MPI_Allreduce(MPI_IN_PLACE, my_array, nvalues, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(nvalues)
#endif
}

void ProcessManager::or_all(bool* boolean)
{
#ifdef BUILDING_WITH_MPI
    MPI_Allreduce(MPI_IN_PLACE, boolean, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD);
#else
    Q_UNUSED(boolean)
#endif

}

//////////////////////////////////////////////////////////////////////

void ProcessManager::broadcast(double* my_array, int nvalues, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Bcast(my_array, nvalues, MPI_DOUBLE, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(nvalues) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::broadcast(int* value, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Bcast(value, 1, MPI_INT, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(value) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

bool ProcessManager::isRoot()
{
#ifdef BUILDING_WITH_MPI
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    return (rank == 0);
#else
    return true;
#endif
}

//////////////////////////////////////////////////////////////////////

bool ProcessManager::isMultiProc()
{
#ifdef BUILDING_WITH_MPI
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    return (size > 1);
#else
    return false;
#endif
}

//////////////////////////////////////////////////////////////////////
<commit_msg>Add preprocessor directives for compiling without MPI<commit_after>/*//////////////////////////////////////////////////////////////////
////       SKIRT -- an advanced radiative transfer code         ////
////       © Astronomical Observatory, Ghent University         ////
///////////////////////////////////////////////////////////////// */

#ifdef BUILDING_WITH_MPI
#include <mpi.h>
#endif

#include "ProcessManager.hpp"
#include <QDataStream>

////////////////////////////////////////////////////////////////////

#ifdef BUILDING_WITH_MPI
namespace
{
    void createDisplacedDoubleBlocks(int blocklength, const std::vector<int>& displacements, MPI_Datatype* newtypeP,
                                     int extent = -1)
    {
        int count = displacements.size();

        // Multiply the displacements by the block length
        std::vector<int> multiplied_disp;
        multiplied_disp.reserve(count);
        for(auto i: displacements) multiplied_disp.push_back(blocklength*i);

        // Create a datatype representing a structure of displaced blocks of the same size;
        MPI_Datatype indexedBlock;
        MPI_Type_create_indexed_block(count, blocklength, &multiplied_disp[0], MPI_DOUBLE, &indexedBlock);

        // Pad this datatype to modify the extent to the requested value
        MPI_Aint lb;
        MPI_Aint ex;
        MPI_Type_get_extent(indexedBlock, &lb, &ex);

        if (extent != -1)
        {
            MPI_Type_create_resized(indexedBlock, lb, extent*sizeof(double), newtypeP);
            // Commit the final type and free the intermediary one
            MPI_Type_commit(newtypeP);
            MPI_Type_free(&indexedBlock);
        }
        else
        {
            // No padding, just store the indexed block
            *newtypeP = indexedBlock;
            MPI_Type_commit(newtypeP);
        }
    }
}
#endif

std::atomic<int> ProcessManager::requests(0);

//////////////////////////////////////////////////////////////////////

void ProcessManager::initialize(int *argc, char ***argv)
{
#ifdef BUILDING_WITH_MPI
    int initialized;
    MPI_Initialized(&initialized);
    if (!initialized)
    {
        MPI_Init(argc, argv);
    }
#else
    Q_UNUSED(argc) Q_UNUSED(argv)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::finalize()
{
#ifdef BUILDING_WITH_MPI
    MPI_Finalize();
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::acquireMPI(int& rank, int& Nprocs)
{
#ifdef BUILDING_WITH_MPI
    int oldrequests = requests++;

    if (oldrequests) // if requests >=1
    {
        Nprocs = 1;
        rank = 0;
    }
    else // requests == 0
    {
        MPI_Comm_size(MPI_COMM_WORLD, &Nprocs);
        MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    }
#else
    rank = 0;
    Nprocs = 1;
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::releaseMPI()
{
#ifdef BUILDING_WITH_MPI
    requests--;
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::barrier()
{
#ifdef BUILDING_WITH_MPI
    MPI_Barrier(MPI_COMM_WORLD);
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sendByteBuffer(QByteArray& buffer, int receiver, int tag)
{
#ifdef BUILDING_WITH_MPI
    MPI_Send(buffer.data(), buffer.size(), MPI_BYTE, receiver, tag, MPI_COMM_WORLD);
#else
    Q_UNUSED(buffer) Q_UNUSED(receiver) Q_UNUSED(tag)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::receiveByteBuffer(QByteArray& buffer, int& sender)
{
#ifdef BUILDING_WITH_MPI
    MPI_Status status;
    MPI_Recv(buffer.data(), buffer.size(), MPI_BYTE, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    sender = status.MPI_SOURCE;
#else
    Q_UNUSED(buffer) Q_UNUSED(sender)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::receiveByteBuffer(QByteArray &buffer, int sender, int& tag)
{
#ifdef BUILDING_WITH_MPI
    MPI_Status status;
    MPI_Recv(buffer.data(), buffer.size(), MPI_BYTE, sender, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
    tag = status.MPI_TAG;
#else
    Q_UNUSED(buffer) Q_UNUSED(sender) Q_UNUSED(tag)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::gatherw(double* sendBuffer, int sendCount,
                             double* recvBuffer, int recvRank, int recvLength,
                             const std::vector<std::vector<int>>& recvDisplacements)
{
#ifdef BUILDING_WITH_MPI
    int size;
    int rank;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);

    // parameters for the senders
    std::vector<int> sendcnts(size, 0);                     // every process sends nothing to all processes
    sendcnts[recvRank] = sendCount;                         // except to the receiver
    std::vector<int> sdispls(size, 0);                      // starting from sendBuffer + 0
    std::vector<MPI_Datatype> sendtypes(size, MPI_DOUBLE);  // all doubles

    // parameters on the receiving end
    std::vector<int> recvcnts;
    if (rank != recvRank) recvcnts.resize(size, 0); // I am not receiver: receive nothing from every process
    else recvcnts.resize(size, 1);                  // I am receiver: receive 1 from every process
    std::vector<int> rdispls(size, 0);              // displacements will be contained in the datatypes
    std::vector<MPI_Datatype> recvtypes;            // we will construct derived datatypes for receiving from each process
    recvtypes.reserve(size);

    for (int r=0; r<size; r++)
    {
        MPI_Datatype newtype;
        createDisplacedDoubleBlocks(recvLength, recvDisplacements[r], &newtype);
        recvtypes.push_back(newtype);
    }

    MPI_Alltoallw(sendBuffer, &sendcnts[0], &sdispls[0], &sendtypes[0],
                  recvBuffer, &recvcnts[0], &rdispls[0], &recvtypes[0],
                  MPI_COMM_WORLD);

    for (int rank=0; rank<size; rank++) MPI_Type_free(&recvtypes[rank]);
#else
    Q_UNUSED(sendBuffer) Q_UNUSED(sendCount) Q_UNUSED(recvBuffer) Q_UNUSED(recvRank) Q_UNUSED(recvLength) Q_UNUSED(recvDisplacements)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::displacedBlocksAllToAll(double* sendBuffer, int sendCount,
                                             const std::vector<std::vector<int>>& sendDisplacements, int sendLength,
                                             int sendExtent, double* recvBuffer, int recvCount,
                                             const std::vector<std::vector<int>>& recvDisplacements, int recvLength,
                                             int recvExtent)
{
#ifdef BUILDING_WITH_MPI
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);

    std::vector<int> sendcnts(size,sendCount);
    std::vector<int> sdispls(size, 0);
    std::vector<MPI_Datatype> sendtypes;
    sendtypes.reserve(size);

    std::vector<int> recvcnts(size, recvCount);
    std::vector<int> rdispls(size, 0);
    std::vector<MPI_Datatype> recvtypes;
    recvtypes.reserve(size);

    for (int r=0; r<size; r++)
    {
        MPI_Datatype newtype;
        createDisplacedDoubleBlocks(sendLength, sendDisplacements[r], &newtype, sendExtent);
        sendtypes.push_back(newtype);

        createDisplacedDoubleBlocks(recvLength, recvDisplacements[r], &newtype, recvExtent);
        recvtypes.push_back(newtype);
    }

    MPI_Alltoallw(sendBuffer, &sendcnts[0], &sdispls[0], &sendtypes[0],
                  recvBuffer, &recvcnts[0], &rdispls[0], &recvtypes[0],
                  MPI_COMM_WORLD);

    for (int r=0; r<size; r++)
    {
        MPI_Type_free(&sendtypes[r]);
        MPI_Type_free(&recvtypes[r]);
    }
#else
    Q_UNUSED(sendBuffer) Q_UNUSED(sendCount) Q_UNUSED(sendDisplacements) Q_UNUSED(sendLength) Q_UNUSED(sendExtent)
    Q_UNUSED(recvBuffer) Q_UNUSED(recvCount) Q_UNUSED(recvDisplacements) Q_UNUSED(recvLength) Q_UNUSED(recvExtent)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sum(double* my_array, double* result_array, int nvalues, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Reduce(my_array, result_array, nvalues, MPI_DOUBLE, MPI_SUM, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(result_array) Q_UNUSED(nvalues) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::sum_all(double* my_array, int nvalues)
{
#ifdef BUILDING_WITH_MPI
    MPI_Allreduce(MPI_IN_PLACE, my_array, nvalues, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(nvalues)
#endif
}

void ProcessManager::or_all(bool* boolean)
{
#ifdef BUILDING_WITH_MPI
    MPI_Allreduce(MPI_IN_PLACE, boolean, 1, MPI_C_BOOL, MPI_LOR, MPI_COMM_WORLD);
#else
    Q_UNUSED(boolean)
#endif

}

//////////////////////////////////////////////////////////////////////

void ProcessManager::broadcast(double* my_array, int nvalues, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Bcast(my_array, nvalues, MPI_DOUBLE, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(my_array) Q_UNUSED(nvalues) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

void ProcessManager::broadcast(int* value, int root)
{
#ifdef BUILDING_WITH_MPI
    MPI_Bcast(value, 1, MPI_INT, root, MPI_COMM_WORLD);
#else
    Q_UNUSED(value) Q_UNUSED(root)
#endif
}

//////////////////////////////////////////////////////////////////////

bool ProcessManager::isRoot()
{
#ifdef BUILDING_WITH_MPI
    int rank;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    return (rank == 0);
#else
    return true;
#endif
}

//////////////////////////////////////////////////////////////////////

bool ProcessManager::isMultiProc()
{
#ifdef BUILDING_WITH_MPI
    int size;
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    return (size > 1);
#else
    return false;
#endif
}

//////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "Core/Common.h"
#include "Core/Assembler.h"
#include "CommandLineInterface.h"

static void printUsage(std::wstring executableName)
{
	Logger::printLine(L"armips assembler v%d.%d.%d (%s %s) by Kingcom",
		ARMIPS_VERSION_MAJOR, ARMIPS_VERSION_MINOR, ARMIPS_VERSION_REVISION, __DATE__, __TIME__);
	Logger::printLine(L"Usage: %s [optional parameters] <FILE>", executableName);
	Logger::printLine(L"");
	Logger::printLine(L"Optional parameters:");
	Logger::printLine(L" -temp <TEMP>              Output temporary assembly data to <TEMP> file");
	Logger::printLine(L" -sym  <SYM>               Output symbol data in the sym format to <SYM> file");
	Logger::printLine(L" -sym2 <SYM2>              Output symbol data in the sym2 format to <SYM2> file");
	Logger::printLine(L" -root <ROOT>              Use <ROOT> as working directory during execution");
	Logger::printLine(L" -equ  <NAME> <VAL>        Equivalent to \'<NAME> equ <VAL>\' in code");
	Logger::printLine(L" -strequ <NAME> <VAL>      Equivalent to \'<NAME> equ \"<VAL>\"\' in code");
	Logger::printLine(L" -definelabel <NAME> <VAL> Equivalent to \'.definelabel <NAME>, <VAL>\' in code");
	Logger::printLine(L" -erroronwarning           Treat all warnings like errors");
	Logger::printLine(L"");
	Logger::printLine(L"File arguments:");
	Logger::printLine(L" <FILE>                    Main assembly code file");
}

static bool parseArguments(const StringList& arguments, ArmipsArguments& settings)
{
	size_t argpos = 1;
	bool readflags = true;
	while (argpos < arguments.size())
	{
		if (readflags && arguments[argpos][0] == L'-')
		{
			if (arguments[argpos] == L"--")
			{
				readflags = false;
				argpos += 1;
			}
			else if (arguments[argpos] == L"-temp" && argpos + 1 < arguments.size())
			{
				settings.tempFileName = arguments[argpos + 1];
				argpos += 2;
			}
			else if (arguments[argpos] == L"-sym" && argpos + 1 < arguments.size())
			{
				settings.symFileName = arguments[argpos + 1];
				settings.symFileVersion = 1;
				argpos += 2;
			}
			else if (arguments[argpos] == L"-sym2" && argpos + 1 < arguments.size())
			{
				settings.symFileName = arguments[argpos + 1];
				settings.symFileVersion = 2;
				argpos += 2;
			}
			else if (arguments[argpos] == L"-erroronwarning")
			{
				settings.errorOnWarning = true;
				argpos += 1;
			}
			else if (arguments[argpos] == L"-equ" && argpos + 2 < arguments.size())
			{
				EquationDefinition def;
				def.name = arguments[argpos + 1];

				if (!checkValidLabelName(def.name))
				{
					Logger::printError(Logger::Error, L"Invalid equation name %s", def.name);
					return false;
				}

				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);
				def.value = arguments[argpos + 2];
				settings.equList.push_back(def);
				argpos += 3;
			}
			else if (arguments[argpos] == L"-strequ" && argpos + 2 < arguments.size())
			{
				EquationDefinition def;
				def.name = arguments[argpos + 1];

				if (!checkValidLabelName(def.name))
				{
					Logger::printError(Logger::Error, L"Invalid equation name %s", def.name);
					return false;
				}

				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);
				def.value = formatString(L"\"%s\"", arguments[argpos + 2]);
				settings.equList.push_back(def);
				argpos += 3;
			}
			else if (arguments[argpos] == L"-time")
			{
				Logger::printError(Logger::Warning, L"-time flag is deprecated");
				argpos += 1;
			}
			else if (arguments[argpos] == L"-root" && argpos + 1 < arguments.size())
			{
				if(!changeDirectory(arguments[argpos + 1]))
				{
					Logger::printError(Logger::Error, L"Could not open directory '%s'", arguments[argpos + 1]);
					return false;
				}
				argpos += 2;
			}
			else if (arguments[argpos] == L"-definelabel" && argpos + 2 < arguments.size())
			{
				LabelDefinition def;

				def.originalName = arguments[argpos + 1];

				if (!checkValidLabelName(def.originalName))
				{
					Logger::printError(Logger::Error, L"Invalid definelabel name %s", def.originalName);
					return false;
				}

				def.name = def.originalName;
				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);

				int64_t value;
				if (!stringToInt(arguments[argpos + 2], 0, arguments[argpos + 2].size(), value))
				{
					Logger::printError(Logger::Error, L"Invalid definelabel value '%s'\n", arguments[argpos + 2]);
					return false;
				}
				def.value = value;

				settings.labels.push_back(def);
				argpos += 3;
			}
			else {
				Logger::printError(Logger::Error, L"Invalid command line argument '%s'\n", arguments[argpos]);
				printUsage(arguments[0]);
				return false;
			}
		}
		else {
			// only allow one input filename
			if (settings.inputFileName == L"")
			{
				settings.inputFileName = arguments[argpos];
				argpos++;
			}
			else {
				Logger::printError(Logger::Error, L"Multiple input assembly files specified\n");
				printUsage(arguments[0]);
				return false;
			}
		}
	}

	// ensure input file was specified
	if (settings.inputFileName == L"")
	{
		if (arguments.size() > 1)
			Logger::printError(Logger::Error, L"Missing input assembly file\n");

		printUsage(arguments[0]);
		return false;
	}

	// turn input filename into an absolute path
	if (settings.useAbsoluteFileNames && isAbsolutePath(settings.inputFileName) == false)
		settings.inputFileName = formatString(L"%s/%s", getCurrentDirectory(), settings.inputFileName);

	if (fileExists(settings.inputFileName) == false)
	{
		Logger::printError(Logger::Error, L"File '%s' not found", settings.inputFileName);
		return false;
	}
	return true;
}

int runFromCommandLine(const StringList& arguments, ArmipsArguments settings)
{
	if (parseArguments(arguments, settings) == false)
	{
		if (!settings.silent)
			Logger::printLine(L"Cannot parse arguments; aborting.");

		return 1;
	}

	if (runArmips(settings) == false)
	{
		if (!settings.silent)
			Logger::printLine(L"Aborting.");

		return 1;
	}

	return 0;
}
<commit_msg>Check that -strequ/-equ/-definelabel names do not have multiple definitions<commit_after>#include "stdafx.h"
#include "Core/Common.h"
#include "Core/Assembler.h"
#include "CommandLineInterface.h"

static void printUsage(std::wstring executableName)
{
	Logger::printLine(L"armips assembler v%d.%d.%d (%s %s) by Kingcom",
		ARMIPS_VERSION_MAJOR, ARMIPS_VERSION_MINOR, ARMIPS_VERSION_REVISION, __DATE__, __TIME__);
	Logger::printLine(L"Usage: %s [optional parameters] <FILE>", executableName);
	Logger::printLine(L"");
	Logger::printLine(L"Optional parameters:");
	Logger::printLine(L" -temp <TEMP>              Output temporary assembly data to <TEMP> file");
	Logger::printLine(L" -sym  <SYM>               Output symbol data in the sym format to <SYM> file");
	Logger::printLine(L" -sym2 <SYM2>              Output symbol data in the sym2 format to <SYM2> file");
	Logger::printLine(L" -root <ROOT>              Use <ROOT> as working directory during execution");
	Logger::printLine(L" -equ  <NAME> <VAL>        Equivalent to \'<NAME> equ <VAL>\' in code");
	Logger::printLine(L" -strequ <NAME> <VAL>      Equivalent to \'<NAME> equ \"<VAL>\"\' in code");
	Logger::printLine(L" -definelabel <NAME> <VAL> Equivalent to \'.definelabel <NAME>, <VAL>\' in code");
	Logger::printLine(L" -erroronwarning           Treat all warnings like errors");
	Logger::printLine(L"");
	Logger::printLine(L"File arguments:");
	Logger::printLine(L" <FILE>                    Main assembly code file");
}

static bool parseArguments(const StringList& arguments, ArmipsArguments& settings)
{
	size_t argpos = 1;
	bool readflags = true;
	while (argpos < arguments.size())
	{
		if (readflags && arguments[argpos][0] == L'-')
		{
			if (arguments[argpos] == L"--")
			{
				readflags = false;
				argpos += 1;
			}
			else if (arguments[argpos] == L"-temp" && argpos + 1 < arguments.size())
			{
				settings.tempFileName = arguments[argpos + 1];
				argpos += 2;
			}
			else if (arguments[argpos] == L"-sym" && argpos + 1 < arguments.size())
			{
				settings.symFileName = arguments[argpos + 1];
				settings.symFileVersion = 1;
				argpos += 2;
			}
			else if (arguments[argpos] == L"-sym2" && argpos + 1 < arguments.size())
			{
				settings.symFileName = arguments[argpos + 1];
				settings.symFileVersion = 2;
				argpos += 2;
			}
			else if (arguments[argpos] == L"-erroronwarning")
			{
				settings.errorOnWarning = true;
				argpos += 1;
			}
			else if (arguments[argpos] == L"-equ" && argpos + 2 < arguments.size())
			{
				EquationDefinition def;

				auto originalName = arguments[argpos+1];
				def.name = originalName;
				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);

				if (!checkValidLabelName(originalName))
				{
					Logger::printError(Logger::Error, L"Invalid equation name %s", originalName);
					return false;
				}

				auto it = std::find_if(settings.equList.begin(), settings.equList.end(),
						[&def](EquationDefinition x) -> bool {return def.name == x.name;});
				if(it != settings.equList.end())
				{
					Logger::printError(Logger::Error, L"Equation name %s defined more than once", originalName);
					return false;
				}

				def.value = arguments[argpos + 2];
				settings.equList.push_back(def);
				argpos += 3;
			}
			else if (arguments[argpos] == L"-strequ" && argpos + 2 < arguments.size())
			{
				EquationDefinition def;

				auto originalName = arguments[argpos+1];
				def.name = originalName;
				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);

				if (!checkValidLabelName(originalName))
				{
					Logger::printError(Logger::Error, L"Invalid equation name %s", originalName);
					return false;
				}

				auto it = std::find_if(settings.equList.begin(), settings.equList.end(),
						[&def](EquationDefinition x) -> bool {return def.name == x.name;});
				if(it != settings.equList.end())
				{
					Logger::printError(Logger::Error, L"Equation name %s defined more than once", originalName);
					return false;
				}

				def.value = formatString(L"\"%s\"", arguments[argpos + 2]);
				settings.equList.push_back(def);
				argpos += 3;
			}
			else if (arguments[argpos] == L"-time")
			{
				Logger::printError(Logger::Warning, L"-time flag is deprecated");
				argpos += 1;
			}
			else if (arguments[argpos] == L"-root" && argpos + 1 < arguments.size())
			{
				if(!changeDirectory(arguments[argpos + 1]))
				{
					Logger::printError(Logger::Error, L"Could not open directory '%s'", arguments[argpos + 1]);
					return false;
				}
				argpos += 2;
			}
			else if (arguments[argpos] == L"-definelabel" && argpos + 2 < arguments.size())
			{
				LabelDefinition def;

				def.originalName = arguments[argpos + 1];
				def.name = def.originalName;
				std::transform(def.name.begin(), def.name.end(), def.name.begin(), ::towlower);

				if (!checkValidLabelName(def.originalName))
				{
					Logger::printError(Logger::Error, L"Invalid label name %s", def.originalName);
					return false;
				}

				auto it = std::find_if(settings.labels.begin(), settings.labels.end(),
						[&def](LabelDefinition x) -> bool {return def.name == x.name;});
				if(it != settings.labels.end())
				{
					Logger::printError(Logger::Error, L"Label name %s defined more than once", def.originalName);
					return false;
				}

				int64_t value;
				if (!stringToInt(arguments[argpos + 2], 0, arguments[argpos + 2].size(), value))
				{
					Logger::printError(Logger::Error, L"Invalid label value '%s'\n", arguments[argpos + 2]);
					return false;
				}
				def.value = value;

				settings.labels.push_back(def);
				argpos += 3;
			}
			else {
				Logger::printError(Logger::Error, L"Invalid command line argument '%s'\n", arguments[argpos]);
				printUsage(arguments[0]);
				return false;
			}
		}
		else {
			// only allow one input filename
			if (settings.inputFileName == L"")
			{
				settings.inputFileName = arguments[argpos];
				argpos++;
			}
			else {
				Logger::printError(Logger::Error, L"Multiple input assembly files specified\n");
				printUsage(arguments[0]);
				return false;
			}
		}
	}

	// ensure input file was specified
	if (settings.inputFileName == L"")
	{
		if (arguments.size() > 1)
			Logger::printError(Logger::Error, L"Missing input assembly file\n");

		printUsage(arguments[0]);
		return false;
	}

	// turn input filename into an absolute path
	if (settings.useAbsoluteFileNames && isAbsolutePath(settings.inputFileName) == false)
		settings.inputFileName = formatString(L"%s/%s", getCurrentDirectory(), settings.inputFileName);

	if (fileExists(settings.inputFileName) == false)
	{
		Logger::printError(Logger::Error, L"File '%s' not found", settings.inputFileName);
		return false;
	}
	return true;
}

int runFromCommandLine(const StringList& arguments, ArmipsArguments settings)
{
	if (parseArguments(arguments, settings) == false)
	{
		if (arguments.size() > 1 && !settings.silent)
			Logger::printLine(L"Cannot parse arguments; aborting.");

		return 1;
	}

	if (runArmips(settings) == false)
	{
		if (!settings.silent)
			Logger::printLine(L"Aborting.");

		return 1;
	}

	return 0;
}
<|endoftext|>