<commit_before>//===--- ClangModuleDependencyScanner.cpp - Dependency Scanning -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements dependency scanning for Clang modules.
//
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"

using namespace swift;

using namespace clang::tooling;
using namespace clang::tooling::dependencies;

class swift::ClangModuleDependenciesCacheImpl {
  /// Cache the names of the files used for the "import hack" to compute module
  /// dependencies.
  /// FIXME: This should go away once Clang's dependency scanning library
  /// can scan by module name.
  llvm::StringMap<std::string> importHackFileCache;

public:
  /// Set containing all of the Clang modules that have already been seen.
  llvm::StringSet<> alreadySeen;

  DependencyScanningService service;

  DependencyScanningTool tool;

  ClangModuleDependenciesCacheImpl()
      : importHackFileCache(),
        service(ScanningMode::MinimizedSourcePreprocessing, ScanningOutputFormat::Full),
        tool(service) { }
  ~ClangModuleDependenciesCacheImpl();

  /// Retrieve the name of the file used for the "import hack" that is
  /// used to scan the dependencies of a Clang module.
  llvm::ErrorOr<StringRef> getImportHackFile(StringRef moduleName);
};

ClangModuleDependenciesCacheImpl::~ClangModuleDependenciesCacheImpl() {
  if (!importHackFileCache.empty()) {
    for (auto& it: importHackFileCache) {
      llvm::sys::fs::remove(it.second);
    }
  }
}

llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile(StringRef moduleName) {
  auto cacheIt = importHackFileCache.find(moduleName.str());
  if (cacheIt != importHackFileCache.end())
    return cacheIt->second;

  // Create a temporary file.
  int resultFD;
  SmallString<128> resultPath;
  if (auto error = llvm::sys::fs::createTemporaryFile(
          "import-hack-" + moduleName.str(), "c", resultFD, resultPath))
    return error;

  llvm::raw_fd_ostream out(resultFD, /*shouldClose=*/true);
  out << "#pragma clang module import " << moduleName.str() << ";\n";
  llvm::sys::RemoveFileOnSignal(resultPath);
  importHackFileCache.insert(std::make_pair(moduleName, resultPath.str().str()));
  return importHackFileCache[moduleName];
}

// Add search paths.
// Note: This is handled differently for the Clang importer itself, which
// adds search paths to Clang's data structures rather than to its
// command line.
static void addSearchPathInvocationArguments(
    std::vector<std::string> &invocationArgStrs, ASTContext &ctx) {
  SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
  for (const auto &framepath : searchPathOpts.getFrameworkSearchPaths()) {
    invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F");
    invocationArgStrs.push_back(framepath.Path);
  }

  for (const auto &path : searchPathOpts.getImportSearchPaths()) {
    invocationArgStrs.push_back("-I");
    invocationArgStrs.push_back(path);
  }
}

/// Create the command line for Clang dependency scanning.
static std::vector<std::string> getClangDepScanningInvocationArguments(
    ASTContext &ctx,
    StringRef sourceFileName) {
  std::vector<std::string> commandLineArgs;

  // Form the basic command line.
  commandLineArgs.push_back("clang");
  importer::getNormalInvocationArguments(commandLineArgs, ctx);
  importer::addCommonInvocationArguments(commandLineArgs, ctx);
  addSearchPathInvocationArguments(commandLineArgs, ctx);

  auto sourceFilePos = std::find(
      commandLineArgs.begin(), commandLineArgs.end(),
      "<swift-imported-modules>");
  assert(sourceFilePos != commandLineArgs.end());
  *sourceFilePos = sourceFileName.str();

  // HACK! Drop the -fmodule-format= argument and the one that
  // precedes it.
  {
    auto moduleFormatPos = std::find_if(commandLineArgs.begin(),
                                        commandLineArgs.end(),
                                        [](StringRef arg) {
      return arg.startswith("-fmodule-format=");
    });
    assert(moduleFormatPos != commandLineArgs.end());
    assert(moduleFormatPos != commandLineArgs.begin());
    commandLineArgs.erase(moduleFormatPos-1, moduleFormatPos+1);
  }

  // HACK: No -fsyntax-only here?
  {
    auto syntaxOnlyPos = std::find(commandLineArgs.begin(),
                                   commandLineArgs.end(),
                                   "-fsyntax-only");
    assert(syntaxOnlyPos != commandLineArgs.end());
    *syntaxOnlyPos = "-c";
  }

  // HACK: Stolen from ClangScanDeps.cpp
  commandLineArgs.push_back("-o");
  commandLineArgs.push_back("/dev/null");
  commandLineArgs.push_back("-M");
  commandLineArgs.push_back("-MT");
  commandLineArgs.push_back("import-hack.o");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-Eonly");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-sys-header-deps");
  commandLineArgs.push_back("-Wno-error");

  return commandLineArgs;
}

/// Get or create the Clang-specific
static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
    ModuleDependenciesCache &cache) {
  auto clangImpl = cache.getClangImpl();
  if (!clangImpl) {
    clangImpl = new ClangModuleDependenciesCacheImpl();
    cache.setClangImpl(clangImpl,
                       [](ClangModuleDependenciesCacheImpl *ptr) {
      delete ptr;
    });
  }

  return clangImpl;
}

/// Record the module dependencies we found by scanning Clang modules into
/// the module dependencies cache.
void ClangImporter::recordModuleDependencies(
    ModuleDependenciesCache &cache,
    const FullDependenciesResult &clangDependencies) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();

  // This scanner invocation's already-captured APINotes version
  std::vector<std::string> capturedPCMArgs = {
    "-Xcc",
    ("-fapinotes-swift-version=" +
     ctx.LangOpts.EffectiveLanguageVersion.asAPINotesVersionString())
  };

  for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
    // If we've already cached this information, we're done.
    if (cache.hasDependencies(
                    clangModuleDep.ID.ModuleName,
                    {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet}))
      continue;

    // File dependencies for this module.
    std::vector<std::string> fileDeps;
    for (const auto &fileDep : clangModuleDep.FileDeps) {
      fileDeps.push_back(fileDep.getKey().str());
    }
    // Inherit all Clang driver args when creating the clang importer.
    ArrayRef<std::string> allArgs = Impl.ClangArgs;
    ClangImporterOptions Opts;

    // Ensure the arguments we collected is sufficient to create a Clang
    // invocation.
    assert(createClangInvocation(this, Opts, nullptr, allArgs));

    std::vector<std::string> swiftArgs;
    // We are using Swift frontend mode.
    swiftArgs.push_back("-frontend");
    // We pass the entire argument list via -Xcc, so the invocation should
    // use extra clang options alone.
    swiftArgs.push_back("-only-use-extra-clang-opts");
    auto addClangArg = [&](Twine arg) {
      swiftArgs.push_back("-Xcc");
      swiftArgs.push_back(arg.str());
    };
    auto addClangFrontendArg = [&](Twine arg) {
      addClangArg("-Xclang");
      addClangArg(arg);
    };

    // Add all args inherited from creating the importer.
    auto It = allArgs.begin();

    {
      StringRef arg = *It;
      if (arg == "clang" ||
          arg.endswith(llvm::sys::path::get_separator().str() + "clang")) {
        // Remove the initial path to clang executable argument, to avoid
        // treating it as an executable input to compilation. It is not needed
        // because the consumer of this command-line will invoke the emit-PCM
        // action via swift-frontend.
        It += 1;
      }
    }

    while(It != allArgs.end()) {
      StringRef arg = *It;
      // Remove the -target arguments because we should use the target triple
      // specified with `-clang-target` on the scanner invocation, or
      // from the depending Swift modules.
      if (arg == "-target") {
        It += 2;
      } else if (arg.startswith("-fapinotes-swift-version=")) {
        // Remove the apinotes version because we should use the language version
        // specified in the interface file.
        It += 1;
      } else {
        addClangArg(*It);
        ++ It;
      }
    }

    // Add the equivalent of the old `getAdditionalArgsWithoutModulePaths`.
    // TODO: Should we be passing all cc1 args (ie.
    // `getCanonicalCommandLineWithoutModulePaths`)?
    addClangFrontendArg("-fno-implicit-modules");
    addClangFrontendArg("-emit-module");
    addClangFrontendArg(Twine("-fmodule-name=") + clangModuleDep.ID.ModuleName);
    if (clangModuleDep.IsSystem)
      addClangFrontendArg("-fsystem-module");
    if (clangModuleDep.BuildInvocation.getLangOpts()->NeededByPCHOrCompilationUsesPCH)
      addClangFrontendArg("-fmodule-related-to-pch");

    // If the scanner is invoked with '-clang-target', ensure this is the target
    // used to build this PCM.
    if (Impl.SwiftContext.LangOpts.ClangTarget.hasValue()) {
      llvm::Triple triple = Impl.SwiftContext.LangOpts.ClangTarget.getValue();
      addClangArg("-target");
      addClangArg(triple.str());
    }

    // Swift frontend action: -emit-pcm
    swiftArgs.push_back("-emit-pcm");
    swiftArgs.push_back("-module-name");
    swiftArgs.push_back(clangModuleDep.ID.ModuleName);

    // Pass down search paths to the -emit-module action.
    // Unlike building Swift modules, we need to include all search paths to
    // the clang invocation to build PCMs because transitive headers can only
    // be found via search paths. Passing these headers as explicit inputs can
    // be quite challenging.
    for (const auto &path :
         Impl.SwiftContext.SearchPathOpts.getImportSearchPaths()) {
      addClangArg("-I" + path);
    }
    for (const auto &path :
         Impl.SwiftContext.SearchPathOpts.getFrameworkSearchPaths()) {
      addClangArg((path.IsSystem ? "-Fsystem": "-F") + path.Path);
    }

    // Swift frontend option for input file path (Foo.modulemap).
    swiftArgs.push_back(clangModuleDep.ClangModuleMapFile);
    // Module-level dependencies.
    llvm::StringSet<> alreadyAddedModules;
    auto dependencies = ModuleDependencies::forClangModule(
        clangModuleDep.ClangModuleMapFile,
        clangModuleDep.ID.ContextHash,
        swiftArgs,
        fileDeps,
        capturedPCMArgs);
    for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
      dependencies.addModuleDependency(moduleName.ModuleName, &alreadyAddedModules);
    }

    cache.recordDependencies(clangModuleDep.ID.ModuleName,
                             std::move(dependencies));
  }
}

Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
    StringRef moduleName, ModuleDependenciesCache &cache,
    InterfaceSubContextDelegate &delegate) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();
  // Check whether there is already a cached result.
  if (auto found = cache.findDependencies(
          moduleName,
          {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet}))
    return found;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // HACK! Replace the module import buffer name with the source file hack.
  auto importHackFile = clangImpl->getImportHackFile(moduleName);
  if (!importHackFile) {
    // FIXME: Emit a diagnostic here.
    return None;
  }

  // Determine the command-line arguments for dependency scanning.
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(ctx, *importHackFile);
  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      commandLineArgs, workingDir, clangImpl->alreadySeen);
  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return None;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);
            return cache.findDependencies(
                    moduleName,
                    {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet});
}

bool ClangImporter::addBridgingHeaderDependencies(
    StringRef moduleName,
    ModuleDependenciesKind moduleKind,
    ModuleDependenciesCache &cache) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();

  auto targetModule = *cache.findDependencies(
              moduleName,
              {moduleKind,
               currentSwiftSearchPathSet});

  // If we've already recorded bridging header dependencies, we're done.
  if (auto swiftInterfaceDeps = targetModule.getAsSwiftInterfaceModule()) {
    if (!swiftInterfaceDeps->textualModuleDetails.bridgingSourceFiles.empty() ||
        !swiftInterfaceDeps->textualModuleDetails.bridgingModuleDependencies.empty())
      return false;
  } else if (auto swiftSourceDeps = targetModule.getAsSwiftSourceModule()) {
    if (!swiftSourceDeps->textualModuleDetails.bridgingSourceFiles.empty() ||
        !swiftSourceDeps->textualModuleDetails.bridgingModuleDependencies.empty())
      return false;
  } else {
    llvm_unreachable("Unexpected module dependency kind");
  }

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // Retrieve the bridging header.
  std::string bridgingHeader = *targetModule.getBridgingHeader();

  // Determine the command-line arguments for dependency scanning.
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(ctx, bridgingHeader);
  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      commandLineArgs, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return true;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  // Record dependencies for the source files the bridging header includes.
  for (const auto &fileDep : clangDependencies->FullDeps.FileDeps)
    targetModule.addBridgingSourceFile(fileDep);

  // ... and all module dependencies.
  llvm::StringSet<> alreadyAddedModules;
  for (const auto &moduleDep : clangDependencies->FullDeps.ClangModuleDeps) {
    targetModule.addBridgingModuleDependency(
        moduleDep.ModuleName, alreadyAddedModules);
  }

  // Update the cache with the new information for the module.
  cache.updateDependencies(
     {moduleName.str(), moduleKind},
     std::move(targetModule));

  return false;
}
<commit_msg>Update swift to build against cas-support<commit_after>//===--- ClangModuleDependencyScanner.cpp - Dependency Scanning -----------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2019 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
//
// This file implements dependency scanning for Clang modules.
//
//===----------------------------------------------------------------------===//
#include "ImporterImpl.h"
#include "swift/AST/ModuleDependencies.h"
#include "swift/Basic/SourceManager.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningService.h"
#include "clang/Tooling/DependencyScanning/DependencyScanningTool.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Signals.h"

using namespace swift;

using namespace clang::tooling;
using namespace clang::tooling::dependencies;

class swift::ClangModuleDependenciesCacheImpl {
  /// Cache the names of the files used for the "import hack" to compute module
  /// dependencies.
  /// FIXME: This should go away once Clang's dependency scanning library
  /// can scan by module name.
  llvm::StringMap<std::string> importHackFileCache;

public:
  /// Set containing all of the Clang modules that have already been seen.
  llvm::StringSet<> alreadySeen;

  DependencyScanningService service;

  DependencyScanningTool tool;

  ClangModuleDependenciesCacheImpl()
      : importHackFileCache(),
        service(ScanningMode::DependencyDirectivesScan,
                ScanningOutputFormat::Full, clang::CASOptions(), nullptr),
        tool(service) {}
  ~ClangModuleDependenciesCacheImpl();

  /// Retrieve the name of the file used for the "import hack" that is
  /// used to scan the dependencies of a Clang module.
  llvm::ErrorOr<StringRef> getImportHackFile(StringRef moduleName);
};

ClangModuleDependenciesCacheImpl::~ClangModuleDependenciesCacheImpl() {
  if (!importHackFileCache.empty()) {
    for (auto& it: importHackFileCache) {
      llvm::sys::fs::remove(it.second);
    }
  }
}

llvm::ErrorOr<StringRef> ClangModuleDependenciesCacheImpl::getImportHackFile(StringRef moduleName) {
  auto cacheIt = importHackFileCache.find(moduleName.str());
  if (cacheIt != importHackFileCache.end())
    return cacheIt->second;

  // Create a temporary file.
  int resultFD;
  SmallString<128> resultPath;
  if (auto error = llvm::sys::fs::createTemporaryFile(
          "import-hack-" + moduleName.str(), "c", resultFD, resultPath))
    return error;

  llvm::raw_fd_ostream out(resultFD, /*shouldClose=*/true);
  out << "#pragma clang module import " << moduleName.str() << ";\n";
  llvm::sys::RemoveFileOnSignal(resultPath);
  importHackFileCache.insert(std::make_pair(moduleName, resultPath.str().str()));
  return importHackFileCache[moduleName];
}

// Add search paths.
// Note: This is handled differently for the Clang importer itself, which
// adds search paths to Clang's data structures rather than to its
// command line.
static void addSearchPathInvocationArguments(
    std::vector<std::string> &invocationArgStrs, ASTContext &ctx) {
  SearchPathOptions &searchPathOpts = ctx.SearchPathOpts;
  for (const auto &framepath : searchPathOpts.getFrameworkSearchPaths()) {
    invocationArgStrs.push_back(framepath.IsSystem ? "-iframework" : "-F");
    invocationArgStrs.push_back(framepath.Path);
  }

  for (const auto &path : searchPathOpts.getImportSearchPaths()) {
    invocationArgStrs.push_back("-I");
    invocationArgStrs.push_back(path);
  }
}

/// Create the command line for Clang dependency scanning.
static std::vector<std::string> getClangDepScanningInvocationArguments(
    ASTContext &ctx,
    StringRef sourceFileName) {
  std::vector<std::string> commandLineArgs;

  // Form the basic command line.
  commandLineArgs.push_back("clang");
  importer::getNormalInvocationArguments(commandLineArgs, ctx);
  importer::addCommonInvocationArguments(commandLineArgs, ctx);
  addSearchPathInvocationArguments(commandLineArgs, ctx);

  auto sourceFilePos = std::find(
      commandLineArgs.begin(), commandLineArgs.end(),
      "<swift-imported-modules>");
  assert(sourceFilePos != commandLineArgs.end());
  *sourceFilePos = sourceFileName.str();

  // HACK! Drop the -fmodule-format= argument and the one that
  // precedes it.
  {
    auto moduleFormatPos = std::find_if(commandLineArgs.begin(),
                                        commandLineArgs.end(),
                                        [](StringRef arg) {
      return arg.startswith("-fmodule-format=");
    });
    assert(moduleFormatPos != commandLineArgs.end());
    assert(moduleFormatPos != commandLineArgs.begin());
    commandLineArgs.erase(moduleFormatPos-1, moduleFormatPos+1);
  }

  // HACK: No -fsyntax-only here?
  {
    auto syntaxOnlyPos = std::find(commandLineArgs.begin(),
                                   commandLineArgs.end(),
                                   "-fsyntax-only");
    assert(syntaxOnlyPos != commandLineArgs.end());
    *syntaxOnlyPos = "-c";
  }

  // HACK: Stolen from ClangScanDeps.cpp
  commandLineArgs.push_back("-o");
  commandLineArgs.push_back("/dev/null");
  commandLineArgs.push_back("-M");
  commandLineArgs.push_back("-MT");
  commandLineArgs.push_back("import-hack.o");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-Eonly");
  commandLineArgs.push_back("-Xclang");
  commandLineArgs.push_back("-sys-header-deps");
  commandLineArgs.push_back("-Wno-error");

  return commandLineArgs;
}

/// Get or create the Clang-specific
static ClangModuleDependenciesCacheImpl *getOrCreateClangImpl(
    ModuleDependenciesCache &cache) {
  auto clangImpl = cache.getClangImpl();
  if (!clangImpl) {
    clangImpl = new ClangModuleDependenciesCacheImpl();
    cache.setClangImpl(clangImpl,
                       [](ClangModuleDependenciesCacheImpl *ptr) {
      delete ptr;
    });
  }

  return clangImpl;
}

/// Record the module dependencies we found by scanning Clang modules into
/// the module dependencies cache.
void ClangImporter::recordModuleDependencies(
    ModuleDependenciesCache &cache,
    const FullDependenciesResult &clangDependencies) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();

  // This scanner invocation's already-captured APINotes version
  std::vector<std::string> capturedPCMArgs = {
    "-Xcc",
    ("-fapinotes-swift-version=" +
     ctx.LangOpts.EffectiveLanguageVersion.asAPINotesVersionString())
  };

  for (const auto &clangModuleDep : clangDependencies.DiscoveredModules) {
    // If we've already cached this information, we're done.
    if (cache.hasDependencies(
                    clangModuleDep.ID.ModuleName,
                    {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet}))
      continue;

    // File dependencies for this module.
    std::vector<std::string> fileDeps;
    for (const auto &fileDep : clangModuleDep.FileDeps) {
      fileDeps.push_back(fileDep.getKey().str());
    }
    // Inherit all Clang driver args when creating the clang importer.
    ArrayRef<std::string> allArgs = Impl.ClangArgs;
    ClangImporterOptions Opts;

    // Ensure the arguments we collected is sufficient to create a Clang
    // invocation.
    assert(createClangInvocation(this, Opts, nullptr, allArgs));

    std::vector<std::string> swiftArgs;
    // We are using Swift frontend mode.
    swiftArgs.push_back("-frontend");
    // We pass the entire argument list via -Xcc, so the invocation should
    // use extra clang options alone.
    swiftArgs.push_back("-only-use-extra-clang-opts");
    auto addClangArg = [&](Twine arg) {
      swiftArgs.push_back("-Xcc");
      swiftArgs.push_back(arg.str());
    };
    auto addClangFrontendArg = [&](Twine arg) {
      addClangArg("-Xclang");
      addClangArg(arg);
    };

    // Add all args inherited from creating the importer.
    auto It = allArgs.begin();

    {
      StringRef arg = *It;
      if (arg == "clang" ||
          arg.endswith(llvm::sys::path::get_separator().str() + "clang")) {
        // Remove the initial path to clang executable argument, to avoid
        // treating it as an executable input to compilation. It is not needed
        // because the consumer of this command-line will invoke the emit-PCM
        // action via swift-frontend.
        It += 1;
      }
    }

    while(It != allArgs.end()) {
      StringRef arg = *It;
      // Remove the -target arguments because we should use the target triple
      // specified with `-clang-target` on the scanner invocation, or
      // from the depending Swift modules.
      if (arg == "-target") {
        It += 2;
      } else if (arg.startswith("-fapinotes-swift-version=")) {
        // Remove the apinotes version because we should use the language version
        // specified in the interface file.
        It += 1;
      } else {
        addClangArg(*It);
        ++ It;
      }
    }

    // Add the equivalent of the old `getAdditionalArgsWithoutModulePaths`.
    // TODO: Should we be passing all cc1 args (ie.
    // `getCanonicalCommandLineWithoutModulePaths`)?
    addClangFrontendArg("-fno-implicit-modules");
    addClangFrontendArg("-emit-module");
    addClangFrontendArg(Twine("-fmodule-name=") + clangModuleDep.ID.ModuleName);
    if (clangModuleDep.IsSystem)
      addClangFrontendArg("-fsystem-module");
    if (clangModuleDep.BuildInvocation.getLangOpts()->NeededByPCHOrCompilationUsesPCH)
      addClangFrontendArg("-fmodule-related-to-pch");

    // If the scanner is invoked with '-clang-target', ensure this is the target
    // used to build this PCM.
    if (Impl.SwiftContext.LangOpts.ClangTarget.hasValue()) {
      llvm::Triple triple = Impl.SwiftContext.LangOpts.ClangTarget.getValue();
      addClangArg("-target");
      addClangArg(triple.str());
    }

    // Swift frontend action: -emit-pcm
    swiftArgs.push_back("-emit-pcm");
    swiftArgs.push_back("-module-name");
    swiftArgs.push_back(clangModuleDep.ID.ModuleName);

    // Pass down search paths to the -emit-module action.
    // Unlike building Swift modules, we need to include all search paths to
    // the clang invocation to build PCMs because transitive headers can only
    // be found via search paths. Passing these headers as explicit inputs can
    // be quite challenging.
    for (const auto &path :
         Impl.SwiftContext.SearchPathOpts.getImportSearchPaths()) {
      addClangArg("-I" + path);
    }
    for (const auto &path :
         Impl.SwiftContext.SearchPathOpts.getFrameworkSearchPaths()) {
      addClangArg((path.IsSystem ? "-Fsystem": "-F") + path.Path);
    }

    // Swift frontend option for input file path (Foo.modulemap).
    swiftArgs.push_back(clangModuleDep.ClangModuleMapFile);
    // Module-level dependencies.
    llvm::StringSet<> alreadyAddedModules;
    auto dependencies = ModuleDependencies::forClangModule(
        clangModuleDep.ClangModuleMapFile,
        clangModuleDep.ID.ContextHash,
        swiftArgs,
        fileDeps,
        capturedPCMArgs);
    for (const auto &moduleName : clangModuleDep.ClangModuleDeps) {
      dependencies.addModuleDependency(moduleName.ModuleName, &alreadyAddedModules);
    }

    cache.recordDependencies(clangModuleDep.ID.ModuleName,
                             std::move(dependencies));
  }
}

Optional<ModuleDependencies> ClangImporter::getModuleDependencies(
    StringRef moduleName, ModuleDependenciesCache &cache,
    InterfaceSubContextDelegate &delegate) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();
  // Check whether there is already a cached result.
  if (auto found = cache.findDependencies(
          moduleName,
          {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet}))
    return found;

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // HACK! Replace the module import buffer name with the source file hack.
  auto importHackFile = clangImpl->getImportHackFile(moduleName);
  if (!importHackFile) {
    // FIXME: Emit a diagnostic here.
    return None;
  }

  // Determine the command-line arguments for dependency scanning.
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(ctx, *importHackFile);
  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      commandLineArgs, workingDir, clangImpl->alreadySeen);
  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return None;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);
            return cache.findDependencies(
                    moduleName,
                    {ModuleDependenciesKind::Clang, currentSwiftSearchPathSet});
}

bool ClangImporter::addBridgingHeaderDependencies(
    StringRef moduleName,
    ModuleDependenciesKind moduleKind,
    ModuleDependenciesCache &cache) {
  auto &ctx = Impl.SwiftContext;
  auto currentSwiftSearchPathSet = ctx.getAllModuleSearchPathsSet();

  auto targetModule = *cache.findDependencies(
              moduleName,
              {moduleKind,
               currentSwiftSearchPathSet});

  // If we've already recorded bridging header dependencies, we're done.
  if (auto swiftInterfaceDeps = targetModule.getAsSwiftInterfaceModule()) {
    if (!swiftInterfaceDeps->textualModuleDetails.bridgingSourceFiles.empty() ||
        !swiftInterfaceDeps->textualModuleDetails.bridgingModuleDependencies.empty())
      return false;
  } else if (auto swiftSourceDeps = targetModule.getAsSwiftSourceModule()) {
    if (!swiftSourceDeps->textualModuleDetails.bridgingSourceFiles.empty() ||
        !swiftSourceDeps->textualModuleDetails.bridgingModuleDependencies.empty())
      return false;
  } else {
    llvm_unreachable("Unexpected module dependency kind");
  }

  // Retrieve or create the shared state.
  auto clangImpl = getOrCreateClangImpl(cache);

  // Retrieve the bridging header.
  std::string bridgingHeader = *targetModule.getBridgingHeader();

  // Determine the command-line arguments for dependency scanning.
  std::vector<std::string> commandLineArgs =
    getClangDepScanningInvocationArguments(ctx, bridgingHeader);
  std::string workingDir =
      ctx.SourceMgr.getFileSystem()->getCurrentWorkingDirectory().get();

  auto clangDependencies = clangImpl->tool.getFullDependencies(
      commandLineArgs, workingDir, clangImpl->alreadySeen);

  if (!clangDependencies) {
    // FIXME: Route this to a normal diagnostic.
    llvm::logAllUnhandledErrors(clangDependencies.takeError(), llvm::errs());
    return true;
  }

  // Record module dependencies for each module we found.
  recordModuleDependencies(cache, *clangDependencies);

  // Record dependencies for the source files the bridging header includes.
  for (const auto &fileDep : clangDependencies->FullDeps.FileDeps)
    targetModule.addBridgingSourceFile(fileDep);

  // ... and all module dependencies.
  llvm::StringSet<> alreadyAddedModules;
  for (const auto &moduleDep : clangDependencies->FullDeps.ClangModuleDeps) {
    targetModule.addBridgingModuleDependency(
        moduleDep.ModuleName, alreadyAddedModules);
  }

  // Update the cache with the new information for the module.
  cache.updateDependencies(
     {moduleName.str(), moduleKind},
     std::move(targetModule));

  return false;
}
<|endoftext|>


<commit_before>// This code is derived from code distributed as part of Google Perftools.
// The original is available in from google-perftools-2.0 in the file
// src/base/atomicops-internals-x86.cc.  This file was retrieved Feb 06, 2012 by
// Robert Escriva.

/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This module gets enough CPU information to optimize the
 * atomicops module on x86.
 */

// C
#include <cstring>

// e
#include "include/e/atomic.h"

// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
// of the global offset table.  To avoid breaking such executables, this code
// must preserve that register's value across cpuid instructions.
#define cpuid(a, b, c, d, inp) \
  asm ("mov %%rbx, %%rdi\n"    \
       "cpuid\n"               \
       "xchg %%rdi, %%rbx\n"   \
       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))

// Set the flags so that code will run correctly and conservatively
// until InitGoogle() is called.
struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures =
{
    false,          // bug can't exist before process spawns multiple threads
    false,          // no SSE2
    false,          // no cmpxchg16b
};

// Initialize the AtomicOps_Internalx86CPUFeatures struct.
static void AtomicOps_Internalx86CPUFeaturesInit()
{
    uint32_t eax;
    uint32_t ebx;
    uint32_t ecx;
    uint32_t edx;

    // Get vendor string (issue CPUID with eax = 0)
    cpuid(eax, ebx, ecx, edx, 0);
    char vendor[13];
    memcpy(vendor, &ebx, 4);
    memcpy(vendor + 4, &edx, 4);
    memcpy(vendor + 8, &ecx, 4);
    vendor[12] = 0;

    // get feature flags in ecx/edx, and family/model in eax
    cpuid(eax, ebx, ecx, edx, 1);

    int family = (eax >> 8) & 0xf;        // family and model fields
    int model = (eax >> 4) & 0xf;

    if (family == 0xf)
        // use extended family and model fields
    {
        family += (eax >> 20) & 0xff;
        model += ((eax >> 16) & 0xf) << 4;
    }

    // Opteron Rev E has a bug in which on very rare occasions a locked
    // instruction doesn't act as a read-acquire barrier if followed by a
    // non-locked read-modify-write instruction.  Rev F has this bug in
    // pre-release versions, but not in versions released to customers,
    // so we test only for Rev E, which is family 15, model 32..63 inclusive.
    if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
            family == 15 &&
            32 <= model && model <= 63)
    {
        AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
    }
    else
    {
        AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
    }

    // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
    AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);

    // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
    AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
}

class __attribute__ ((visibility ("hidden"))) initializer
{
    public:
        initializer() { AtomicOps_Internalx86CPUFeaturesInit(); }
};

static initializer init;
<commit_msg>Change the "atomic.h" include in atomic.cc<commit_after>// This code is derived from code distributed as part of Google Perftools.
// The original is available in from google-perftools-2.0 in the file
// src/base/atomicops-internals-x86.cc.  This file was retrieved Feb 06, 2012 by
// Robert Escriva.

/* Copyright (c) 2007, Google Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following disclaimer
 * in the documentation and/or other materials provided with the
 * distribution.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * ---
 * This module gets enough CPU information to optimize the
 * atomicops module on x86.
 */

// C
#include <cstring>

// e
#include "e/atomic.h"

// Inline cpuid instruction.  In PIC compilations, %ebx contains the address
// of the global offset table.  To avoid breaking such executables, this code
// must preserve that register's value across cpuid instructions.
#define cpuid(a, b, c, d, inp) \
  asm ("mov %%rbx, %%rdi\n"    \
       "cpuid\n"               \
       "xchg %%rdi, %%rbx\n"   \
       : "=a" (a), "=D" (b), "=c" (c), "=d" (d) : "a" (inp))

// Set the flags so that code will run correctly and conservatively
// until InitGoogle() is called.
struct AtomicOps_x86CPUFeatureStruct AtomicOps_Internalx86CPUFeatures =
{
    false,          // bug can't exist before process spawns multiple threads
    false,          // no SSE2
    false,          // no cmpxchg16b
};

// Initialize the AtomicOps_Internalx86CPUFeatures struct.
static void AtomicOps_Internalx86CPUFeaturesInit()
{
    uint32_t eax;
    uint32_t ebx;
    uint32_t ecx;
    uint32_t edx;

    // Get vendor string (issue CPUID with eax = 0)
    cpuid(eax, ebx, ecx, edx, 0);
    char vendor[13];
    memcpy(vendor, &ebx, 4);
    memcpy(vendor + 4, &edx, 4);
    memcpy(vendor + 8, &ecx, 4);
    vendor[12] = 0;

    // get feature flags in ecx/edx, and family/model in eax
    cpuid(eax, ebx, ecx, edx, 1);

    int family = (eax >> 8) & 0xf;        // family and model fields
    int model = (eax >> 4) & 0xf;

    if (family == 0xf)
        // use extended family and model fields
    {
        family += (eax >> 20) & 0xff;
        model += ((eax >> 16) & 0xf) << 4;
    }

    // Opteron Rev E has a bug in which on very rare occasions a locked
    // instruction doesn't act as a read-acquire barrier if followed by a
    // non-locked read-modify-write instruction.  Rev F has this bug in
    // pre-release versions, but not in versions released to customers,
    // so we test only for Rev E, which is family 15, model 32..63 inclusive.
    if (strcmp(vendor, "AuthenticAMD") == 0 && // AMD
            family == 15 &&
            32 <= model && model <= 63)
    {
        AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = true;
    }
    else
    {
        AtomicOps_Internalx86CPUFeatures.has_amd_lock_mb_bug = false;
    }

    // edx bit 26 is SSE2 which we use to tell use whether we can use mfence
    AtomicOps_Internalx86CPUFeatures.has_sse2 = ((edx >> 26) & 1);

    // ecx bit 13 indicates whether the cmpxchg16b instruction is supported
    AtomicOps_Internalx86CPUFeatures.has_cmpxchg16b = ((ecx >> 13) & 1);
}

class __attribute__ ((visibility ("hidden"))) initializer
{
    public:
        initializer() { AtomicOps_Internalx86CPUFeaturesInit(); }
};

static initializer init;
<|endoftext|>


<commit_before>#include"atoms.hpp"
#include"types.hpp"
#include<stack>
#include<string>
#include<boost/shared_ptr.hpp>
#include<stdexcept>

/*-----------------------------------------------------------------------------
Globals
-----------------------------------------------------------------------------*/
void Globals::get_root_set(std::stack<Generic**>& s){
	std::map<std::string, boost::shared_ptr<Atom> >::iterator i;
	boost::shared_ptr<Atom> ap;
	for(i = string_to_atom.begin(); i != string_to_atom.end(); ++i){
		ap = (*i).second;
		GlobalAtom* gp = dynamic_cast<GlobalAtom*>(&*ap);
		if(gp == NULL){
			throw std::runtime_error("Non-global atom in global atoms list");
		}
		s.push(&gp->value);
	}
}

<commit_msg>atoms: Minor formatting change, checking for unbound variables<commit_after>#include"atoms.hpp"
#include"types.hpp"
#include<stack>
#include<string>
#include<boost/shared_ptr.hpp>
#include<stdexcept>

/*-----------------------------------------------------------------------------
Globals
-----------------------------------------------------------------------------*/
void Globals::get_root_set(std::stack<Generic**>& s){
	std::map<std::string, boost::shared_ptr<Atom> >::iterator i;
	boost::shared_ptr<Atom> ap;
	for(i = string_to_atom.begin(); i != string_to_atom.end(); ++i){
		ap = (*i).second;
		GlobalAtom* gp = dynamic_cast<GlobalAtom*>(&*ap);
		if(gp == NULL){
			throw std::runtime_error(
				"Non-global atom in global atoms list");
		}
		if(gp->value != NULL) s.push(&gp->value);
	}
}

<|endoftext|>


<commit_before>#include "common.h"

#include "hexutil/basics/error.h"

#include "hexav/graphics/graphics.h"
#include "hexav/graphics/font.h"

#define FONT_PATH "c:/windows/fonts/arial.ttf"
#define FONT_PATH_2 "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf"

FontCache font_cache;

FontCache::FontCache() {
    TTF_Init();
}

FontCache::~FontCache() {
    for (auto iter = cache.begin(); iter != cache.end(); iter++) {
        TTF_CloseFont(iter->second);
    }

    TTF_Quit();
}

TTF_Font *FontCache::lookup_font(FontId font_id) {
    if (cache.find(font_id) != cache.end()) {
        return cache[font_id];
    }

    int size;
    if (font_id == SmallFont10)
        size = 10;
    else if (font_id == SmallFont14)
        size = 14;
    else {
        BOOST_LOG_TRIVIAL(error) << "Unknown font: " << font_id;
        return NULL;
    }

    TTF_Font *font = TTF_OpenFont(FONT_PATH, size);
    if (!font)
        font = TTF_OpenFont(FONT_PATH_2, size);
    if (!font) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while opening font: " << TTF_GetError();
        return NULL;
    }
    cache[font_id] = font;
    return font;
}

void TextFormat::write_text(Graphics *graphics, const std::string& text, int x, int y) {
    SDL_Color colour = {R, G, B};
    SDL_Surface *text_surface = TTF_RenderText_Solid(font, text.c_str(), colour);
    if (text_surface == NULL) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
        return;
    }
    SDL_Texture *text_texture = SDL_CreateTextureFromSurface(graphics->renderer, text_surface);

    SDL_Rect dest_rect = { centered ? (x - text_surface->w / 2) : x, centered ? (y - text_surface->h / 2) : y, text_surface->w, text_surface->h };
    SDL_RenderCopy(graphics->renderer, text_texture, NULL, &dest_rect);

    SDL_DestroyTexture(text_texture);
    SDL_FreeSurface(text_surface);

    ++graphics->font_render_counter;
}

Image *TextFormat::write_to_image(Graphics *graphics, const std::string& text) {
    SDL_Color colour = {R, G, B};
    SDL_Surface *text_surface = TTF_RenderText_Solid(font, text.c_str(), colour);
    if (text_surface == NULL) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
        return NULL;
    }

    if (outlined) {
        SDL_Color outline_colour = {outline_R, outline_G, outline_B};
        SDL_Surface *outline_surface = TTF_RenderText_Solid(font, text.c_str(), outline_colour);
        if (outline_surface == NULL) {
            BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
            return NULL;
        }

        SDL_Surface *combined_surface = SDL_CreateRGBSurface(0, text_surface->w+2, text_surface->h+2, 32, 0,0,0,0);
        if (combined_surface == NULL) {
            BOOST_LOG_TRIVIAL(error) << "SDL error while rendering text: " << SDL_GetError();
            return NULL;
        }

        SDL_FillRect(combined_surface, NULL, SDL_MapRGBA(combined_surface->format, 0,0,0,0));
        SDL_SetColorKey(combined_surface, SDL_TRUE, SDL_MapRGBA(combined_surface->format, 0,0,0,0));

        for (int y = 0; y <= 2; y++) {
            for (int x = 0; x <= 2; x++) {
                if (x == 1 && y == 1)
                    continue;
                SDL_Rect dest_rect = { x, y, outline_surface->w, outline_surface->h };
                SDL_BlitSurface(outline_surface, NULL, combined_surface, &dest_rect);
            }
        }
        SDL_Rect dest_rect = { 1, 1, text_surface->w, text_surface->h };
        SDL_BlitSurface(text_surface, NULL, combined_surface, &dest_rect);

        SDL_FreeSurface(text_surface);
        text_surface = combined_surface;
    }

    SDL_Texture *text_texture = SDL_CreateTextureFromSurface(graphics->renderer, text_surface);
    SDL_FreeSurface(text_surface);

    Image *image = new Image(0, text_texture);
    if (centered) {
        image->clip_x_offset -= image->width/2;
        image->clip_y_offset -= image->height/2;
    }

    ++graphics->font_render_counter;

    return image;
}

void TextCache::write_text(const std::string& text, int x, int y) {
    Image *image = NULL;

    auto iter = cache.find(text);
    if (iter != cache.end()) {
        image = iter->second;
    } else {
        //TODO discard least-recently-used entry and free its image

        image = format.write_to_image(graphics, text);
        cache[text] = image;
    }

    graphics->blit(image, x, y, SDL_BLENDMODE_BLEND);
}
<commit_msg>Don't try to render empty strings.<commit_after>#include "common.h"

#include "hexutil/basics/error.h"

#include "hexav/graphics/graphics.h"
#include "hexav/graphics/font.h"

#define FONT_PATH "c:/windows/fonts/arial.ttf"
#define FONT_PATH_2 "/usr/share/fonts/truetype/msttcorefonts/Arial.ttf"

FontCache font_cache;

FontCache::FontCache() {
    TTF_Init();
}

FontCache::~FontCache() {
    for (auto iter = cache.begin(); iter != cache.end(); iter++) {
        TTF_CloseFont(iter->second);
    }

    TTF_Quit();
}

TTF_Font *FontCache::lookup_font(FontId font_id) {
    if (cache.find(font_id) != cache.end()) {
        return cache[font_id];
    }

    int size;
    if (font_id == SmallFont10)
        size = 10;
    else if (font_id == SmallFont14)
        size = 14;
    else {
        BOOST_LOG_TRIVIAL(error) << "Unknown font: " << font_id;
        return NULL;
    }

    TTF_Font *font = TTF_OpenFont(FONT_PATH, size);
    if (!font)
        font = TTF_OpenFont(FONT_PATH_2, size);
    if (!font) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while opening font: " << TTF_GetError();
        return NULL;
    }
    cache[font_id] = font;
    return font;
}

void TextFormat::write_text(Graphics *graphics, const std::string& text, int x, int y) {
    if (text.empty()) {
        return;
    }

    SDL_Color colour = {R, G, B};
    SDL_Surface *text_surface = TTF_RenderText_Solid(font, text.c_str(), colour);
    if (text_surface == NULL) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
        return;
    }
    SDL_Texture *text_texture = SDL_CreateTextureFromSurface(graphics->renderer, text_surface);

    SDL_Rect dest_rect = { centered ? (x - text_surface->w / 2) : x, centered ? (y - text_surface->h / 2) : y, text_surface->w, text_surface->h };
    SDL_RenderCopy(graphics->renderer, text_texture, NULL, &dest_rect);

    SDL_DestroyTexture(text_texture);
    SDL_FreeSurface(text_surface);

    ++graphics->font_render_counter;
}

Image *TextFormat::write_to_image(Graphics *graphics, const std::string& text) {
    if (text.empty()) {
        return nullptr;
    }

    SDL_Color colour = {R, G, B};
    SDL_Surface *text_surface = TTF_RenderText_Solid(font, text.c_str(), colour);
    if (text_surface == NULL) {
        BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
        return NULL;
    }

    if (outlined) {
        SDL_Color outline_colour = {outline_R, outline_G, outline_B};
        SDL_Surface *outline_surface = TTF_RenderText_Solid(font, text.c_str(), outline_colour);
        if (outline_surface == NULL) {
            BOOST_LOG_TRIVIAL(error) << "TTF error while rendering text: " << TTF_GetError();
            return NULL;
        }

        SDL_Surface *combined_surface = SDL_CreateRGBSurface(0, text_surface->w+2, text_surface->h+2, 32, 0,0,0,0);
        if (combined_surface == NULL) {
            BOOST_LOG_TRIVIAL(error) << "SDL error while rendering text: " << SDL_GetError();
            return NULL;
        }

        SDL_FillRect(combined_surface, NULL, SDL_MapRGBA(combined_surface->format, 0,0,0,0));
        SDL_SetColorKey(combined_surface, SDL_TRUE, SDL_MapRGBA(combined_surface->format, 0,0,0,0));

        for (int y = 0; y <= 2; y++) {
            for (int x = 0; x <= 2; x++) {
                if (x == 1 && y == 1)
                    continue;
                SDL_Rect dest_rect = { x, y, outline_surface->w, outline_surface->h };
                SDL_BlitSurface(outline_surface, NULL, combined_surface, &dest_rect);
            }
        }
        SDL_Rect dest_rect = { 1, 1, text_surface->w, text_surface->h };
        SDL_BlitSurface(text_surface, NULL, combined_surface, &dest_rect);

        SDL_FreeSurface(text_surface);
        text_surface = combined_surface;
    }

    SDL_Texture *text_texture = SDL_CreateTextureFromSurface(graphics->renderer, text_surface);
    SDL_FreeSurface(text_surface);

    Image *image = new Image(0, text_texture);
    if (centered) {
        image->clip_x_offset -= image->width/2;
        image->clip_y_offset -= image->height/2;
    }

    ++graphics->font_render_counter;

    return image;
}

void TextCache::write_text(const std::string& text, int x, int y) {
    Image *image = NULL;

    auto iter = cache.find(text);
    if (iter != cache.end()) {
        image = iter->second;
    } else {
        //TODO discard least-recently-used entry and free its image

        image = format.write_to_image(graphics, text);
        cache[text] = image;
    }

    graphics->blit(image, x, y, SDL_BLENDMODE_BLEND);
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Author:   Valient Gough <vgough@pobox.com>
 *
 *****************************************************************************
 * Copyright (c) 2002-2003, Valient Gough
 *
 * This library is free software; you can distribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL), as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the LGPL in the file COPYING for more
 * details.
 *
 */

#include "rlog.h"
#include "rloglocation.h"
#include "RLogPublisher.h"

#include <stdio.h>
#include <stdarg.h>

#include "RLogChannel.h"
#include "Error.h"

#include "Lock.h"

#define UNUSED(x) (void)(x)

#if USE_VALGRIND
#include <valgrind/valgrind.h>
#endif

using namespace std;
using namespace rlog;

extern "C"
int RLogVersion()
{
    return CURRENT_RLOG_VERSION;
}

PublishLoc::~PublishLoc()
{
    disable();
    if(pub != NULL)
    {
	delete pub;
	pub = NULL;
    }
}

void rlog::RLog_Register(PublishLoc *loc, RLogChannel *channel,
	const char *format, ... )
{
    static Mutex registrationLock;
    Lock lock( &registrationLock );

    loc->channel = channel;

    RLogPublisher *pub = new RLogPublisher(loc);

    loc->pub = pub;
    loc->publish = RLogPublisher::Publish;

    if(pub->enabled())
    {
	loc->enable();

	// pass through to the publication function since it is active at
	// birth.
	va_list args;
	va_start (args, format);
	RLogPublisher::PublishVA( loc, channel, format, args );
	va_end( args );
    } else
	loc->disable();
}

/*
    throw an error structure with the file/line/ component data, etc.
*/
void rlog::rAssertFailed(const char *component, const char *file,
	const char *function, int line, const char *conditionStr)
{
#if USE_VALGRIND
    VALGRIND_PRINTF_BACKTRACE("Assert failed: %s", conditionStr);
#endif
    throw Error( component, file, function, line, conditionStr );
}

#if !C99_VARIADAC_MACROS && !PREC99_VARIADAC_MACROS

_rMessageProxy::_rMessageProxy( rlog::RLogChannel *channel,
				rlog::PublishLoc *loc )
{
    this->loc = loc;
    loc->channel = channel;
}

void _rMessageProxy::log(const char *format, ...)
{
    va_list ap;
    va_start( ap, format );
    doLog(format, ap);
    va_end( ap );
}

void _rMessageProxy::doLog(const char *format, va_list ap)
{
    if(!loc->pub)
    {
	loc->publish = RLogPublisher::Publish;

	RLogPublisher *pub = new RLogPublisher(loc);
	loc->pub = pub;

	if(pub->enabled())
	    loc->enable();
	else
	    loc->disable();
    }

    if(loc->isEnabled())
	RLogPublisher::PublishVA( loc, loc->channel, format, ap );
}

void _rMessageProxy::log(RLogChannel *channel, const char *format, ...)
{
    loc->channel = channel;
    va_list ap;
    va_start( ap, format );
    doLog(format, ap);
    va_end( ap );
}

#endif
<commit_msg>fix potential memory leak in registration function with multiple threads<commit_after>/*****************************************************************************
 * Author:   Valient Gough <vgough@pobox.com>
 *
 *****************************************************************************
 * Copyright (c) 2002-2003, Valient Gough
 *
 * This library is free software; you can distribute it and/or modify it under
 * the terms of the GNU Lesser General Public License (LGPL), as published by
 * the Free Software Foundation; either version 2.1 of the License, or (at your
 * option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the LGPL in the file COPYING for more
 * details.
 *
 */

#include "rlog.h"
#include "rloglocation.h"
#include "RLogPublisher.h"

#include <stdio.h>
#include <stdarg.h>

#include "RLogChannel.h"
#include "Error.h"

#include "Lock.h"

#define UNUSED(x) (void)(x)

#if USE_VALGRIND
#include <valgrind/valgrind.h>
#endif

using namespace std;
using namespace rlog;

extern "C"
int RLogVersion()
{
    return CURRENT_RLOG_VERSION;
}

PublishLoc::~PublishLoc()
{
    disable();
    if(pub != NULL)
    {
	delete pub;
	pub = NULL;
    }
}

void rlog::RLog_Register(PublishLoc *loc, RLogChannel *channel,
	const char *format, ... )
{
    static Mutex registrationLock;

    // prevent race with multiple threads registering the same log statement
    {
	Lock lock( &registrationLock );

	if(loc->pub == NULL)
	{
	    loc->channel = channel;
	    loc->publish = RLogPublisher::Publish;

	    RLogPublisher *pub = new RLogPublisher(loc);
	    loc->pub = pub;

	    if(pub->enabled())
		loc->enable();
	    else
		loc->disable();
	}
    }

    if(loc->isEnabled())
    {
	// pass through to the publication function since it is active
	va_list args;
	va_start (args, format);
	RLogPublisher::PublishVA( loc, channel, format, args );
	va_end( args );
    }
}

/*
    throw an error structure with the file/line/ component data, etc.
*/
void rlog::rAssertFailed(const char *component, const char *file,
	const char *function, int line, const char *conditionStr)
{
#if USE_VALGRIND
    VALGRIND_PRINTF_BACKTRACE("Assert failed: %s", conditionStr);
#endif
    throw Error( component, file, function, line, conditionStr );
}

#if !C99_VARIADAC_MACROS && !PREC99_VARIADAC_MACROS

_rMessageProxy::_rMessageProxy( rlog::RLogChannel *channel,
				rlog::PublishLoc *loc )
{
    this->loc = loc;
    loc->channel = channel;
}

void _rMessageProxy::log(const char *format, ...)
{
    va_list ap;
    va_start( ap, format );
    doLog(format, ap);
    va_end( ap );
}

void _rMessageProxy::doLog(const char *format, va_list ap)
{
    if(!loc->pub)
    {
	loc->publish = RLogPublisher::Publish;

	RLogPublisher *pub = new RLogPublisher(loc);
	loc->pub = pub;

	if(pub->enabled())
	    loc->enable();
	else
	    loc->disable();
    }

    if(loc->isEnabled())
	RLogPublisher::PublishVA( loc, loc->channel, format, ap );
}

void _rMessageProxy::log(RLogChannel *channel, const char *format, ...)
{
    loc->channel = channel;
    va_list ap;
    va_start( ap, format );
    doLog(format, ap);
    va_end( ap );
}

#endif
<|endoftext|>


<commit_before>#pragma once

#include <string>
#include <nifty/histogram/histogram.hxx>

#include <nifty/nifty.hxx>

namespace nifty{
namespace graph{
namespace agglo{
namespace merge_rules{

    struct ArithmeticMeanSettings{
        auto name()const{
            return std::string("ArithmeticMean");
        }
    };

    template<class G, class T>
    class ArithmeticMeanEdgeMap{
    public:

        static auto staticName(){
            return std::string("ArithmeticMean");
        }
        auto name()const{
            return staticName();
        }

        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef ArithmeticMeanSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        ArithmeticMeanEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            value *= weight;
            value += oweight*ovalue;
            weight += oweight;
            value /= weight;

        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
    };

    struct GeneralizedMeanSettings{
        GeneralizedMeanSettings(const double p = 1.0)
        : p(p){
        }

        auto name()const{
            return std::string("GeneralizedMean") + std::string("[q=") + std::to_string(p) + std::string("]");
        }
        double p;
    };

    template<class G, class T>
    class  GeneralizedMeanEdgeMap{
    public:

        static auto staticName(){
            return std::string("GeneralizedMean");
        }
        auto name()const{
            return staticName() + std::string("[p=]") + std::to_string(settings_.p);
        }

        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef GeneralizedMeanSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         GeneralizedMeanEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g),
            settings_(settings)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            const auto p = settings_.p;
            const static auto eps = 0.0000001;

            if(std::isinf(p)){
                if(p>0){
                    weight = std::max(weight, oweight);
                }
                else{
                    weight = std::min(weight, oweight);
                }
            }
            else if((p > 1.0-eps) && (p < 1.0 + eps)){
                value *= weight;
                value += oweight*ovalue;
                weight += oweight;
                value /= weight;
            }
            else{
                const auto s = weight + oweight;
                const auto sa = (weight/s ) * std::pow(value, p);
                const auto sd = (oweight/s) * std::pow(ovalue, p);
                value = std::pow(sa+sd, 1.0/p);
                weight = s;
            }
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
        SettingsType settings_;
    };

    struct SmoothMaxSettings{
        double p = {1.0};
        auto name()const{
            return std::string("SmoothMax") + std::string("[q=") + std::to_string(p) + std::string("]");
        }
    };

    template<class G, class T>
    class  SmoothMaxEdgeMap{
    public:

        static auto staticName(){
            return std::string("SmoothMax");
        }
        auto name()const{
            return staticName() + std::string("[q=") + std::to_string(settings_.p) + std::string("]");
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef SmoothMaxSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         SmoothMaxEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g),
            settings_(settings)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            const auto p = settings_.p;
            const static auto eps = 0.0000001;

            if(std::isinf(p)){
                if(p>0){
                    weight = std::max(weight, oweight);
                }
                else{
                    weight = std::min(weight, oweight);
                }
            }
            else if((p > 0.0-eps) && (p < 0.0 + eps)){
                value *= weight;
                value += oweight*ovalue;
                weight += oweight;
                value /= weight;
            }
            else{
                const auto sa = (weight ) * std::exp(value*p);
                const auto sd = (oweight) * std::exp(ovalue*p);

                value =  (value*sa + ovalue*sd)/(sa+sd);
                weight = weight + oweight;
            }
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
        SettingsType settings_;
    };

    struct RankOrderSettings{
        double q = {0.5};
        uint16_t numberOfBins = {50};

        auto name()const{
            std::stringstream ss;
            ss<<"RankOrderEdgeMap [q="<<q<<" #bins="<<numberOfBins<<"]";
            return ss.str();
        }
    };

    template<class G, class T>
    class  RankOrderEdgeMap{
    public:
        static auto staticName(){
            return std::string("RankOrderEdgeMap");
        }
        auto name()const{
            std::stringstream ss;
            ss<<staticName()<<" [q="<<settings_.q<<" #bins="<<settings_.numberOfBins<<"]";
            return ss.str();
        }
        typedef G GraphType;
        typedef nifty::histogram::Histogram<double, double>          HistogramType;
        typedef typename GraphType:: template EdgeMap<HistogramType> HistogramEdgeMapType;
        typedef typename GraphType:: template EdgeMap<T>             SizeEdgeMapType;

        typedef RankOrderSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         RankOrderEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  histogram_(g),
            settings_(settings)
        {
            T minVal =        std::numeric_limits<T>::infinity();
            T maxVal = -1.0 * std::numeric_limits<T>::infinity();

            for(auto edge : g.edges()){

                const auto val = T(values[edge]);
                maxVal = std::max(maxVal, val);
                minVal = std::min(minVal, val);
            }

            for(auto edge : g.edges()){
                auto & hist = histogram_[edge];
                hist.assign(minVal, maxVal, settings_.numberOfBins);
                hist.insert(values[edge], weights[edge]);
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            histogram_[aliveEdge].merge(histogram_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            auto & thist= histogram_[targetEdge];
            const auto &  shist = histogram_[sourceEdge];

            const auto tsum = thist.sum();
            thist = shist;
            thist.normalize(tsum);

        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            histogram_[targetEdge] = histogram_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            auto & hist =  histogram_[targetEdge];
            hist.clearCounts();
            hist.insert(value, weight);
        }

        T operator[](const uint64_t edge)const{
            return histogram_[edge].rank(settings_.q);
        }
    private:
        HistogramEdgeMapType histogram_;
        SettingsType settings_;
    };

    struct MaxSettings{
        auto name()const{
            return std::string("Max");
        }
    };
    template<class G, class T>
    class MaxEdgeMap{
    public:

        static auto staticName(){
            return std::string("Max");
        }
        auto name()const{
            return staticName();
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MaxEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef MaxSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        MaxEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g)
        {
            for(auto edge : g.edges()){
                values_[edge] = values[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            auto & value = values_[aliveEdge];
            value = std::max(value, values_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
        }
        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MaxEdgeMapType values_;
    };

    struct MinSettings{
        auto name()const{
            return std::string("Min");
        }
    };

    template<class G, class T>
    class MinEdgeMap{
    public:

        static auto staticName(){
            return std::string("Min");
        }
        auto name()const{
            return staticName();
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MinEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef MinSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        MinEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g)
        {
            for(auto edge : g.edges()){
                values_[edge] = values[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            auto & value = values_[aliveEdge];
            value = std::min(value, values_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
        }
        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MinEdgeMapType values_;
    };

} // merge rule
} // namespace agglo
} // namespace nifty::graph
} // namespace nifty

<commit_msg>Explicitly define constructor for simple structs SmoothMaxSettings and RankOrderSettings<commit_after>#pragma once

#include <string>
#include <nifty/histogram/histogram.hxx>

#include <nifty/nifty.hxx>

namespace nifty{
namespace graph{
namespace agglo{
namespace merge_rules{

    struct ArithmeticMeanSettings{
        auto name()const{
            return std::string("ArithmeticMean");
        }
    };

    template<class G, class T>
    class ArithmeticMeanEdgeMap{
    public:

        static auto staticName(){
            return std::string("ArithmeticMean");
        }
        auto name()const{
            return staticName();
        }

        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef ArithmeticMeanSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        ArithmeticMeanEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            value *= weight;
            value += oweight*ovalue;
            weight += oweight;
            value /= weight;

        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
    };

    struct GeneralizedMeanSettings{
        GeneralizedMeanSettings(const double p = 1.0)
        : p(p){
        }

        auto name()const{
            return std::string("GeneralizedMean") + std::string("[q=") + std::to_string(p) + std::string("]");
        }
        double p;
    };

    template<class G, class T>
    class  GeneralizedMeanEdgeMap{
    public:

        static auto staticName(){
            return std::string("GeneralizedMean");
        }
        auto name()const{
            return staticName() + std::string("[p=]") + std::to_string(settings_.p);
        }

        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef GeneralizedMeanSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         GeneralizedMeanEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g),
            settings_(settings)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            const auto p = settings_.p;
            const static auto eps = 0.0000001;

            if(std::isinf(p)){
                if(p>0){
                    weight = std::max(weight, oweight);
                }
                else{
                    weight = std::min(weight, oweight);
                }
            }
            else if((p > 1.0-eps) && (p < 1.0 + eps)){
                value *= weight;
                value += oweight*ovalue;
                weight += oweight;
                value /= weight;
            }
            else{
                const auto s = weight + oweight;
                const auto sa = (weight/s ) * std::pow(value, p);
                const auto sd = (oweight/s) * std::pow(ovalue, p);
                value = std::pow(sa+sd, 1.0/p);
                weight = s;
            }
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
        SettingsType settings_;
    };

    struct SmoothMaxSettings{
        double p;
        SmoothMaxSettings(double p = 1.0) : p(p){ }
        auto name()const{
            return std::string("SmoothMax") + std::string("[q=") + std::to_string(p) + std::string("]");
        }
    };

    template<class G, class T>
    class  SmoothMaxEdgeMap{
    public:

        static auto staticName(){
            return std::string("SmoothMax");
        }
        auto name()const{
            return staticName() + std::string("[q=") + std::to_string(settings_.p) + std::string("]");
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MeanEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef SmoothMaxSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         SmoothMaxEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g),
            weights_(g),
            settings_(settings)
        {
            for(auto edge : g.edges()){

                values_[edge] = values[edge];
                weights_[edge] = weights[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){

            auto & value  = values_[aliveEdge];
            auto & weight = weights_[aliveEdge];
            const auto & ovalue  =  values_[deadEdge];
            const auto & oweight = weights_[deadEdge];

            const auto p = settings_.p;
            const static auto eps = 0.0000001;

            if(std::isinf(p)){
                if(p>0){
                    weight = std::max(weight, oweight);
                }
                else{
                    weight = std::min(weight, oweight);
                }
            }
            else if((p > 0.0-eps) && (p < 0.0 + eps)){
                value *= weight;
                value += oweight*ovalue;
                weight += oweight;
                value /= weight;
            }
            else{
                const auto sa = (weight ) * std::exp(value*p);
                const auto sd = (oweight) * std::exp(ovalue*p);

                value =  (value*sa + ovalue*sd)/(sa+sd);
                weight = weight + oweight;
            }
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
            weights_[targetEdge] = weights_[sourceEdge];
        }

        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
            weights_[targetEdge] = weight;
        }

        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MeanEdgeMapType values_;
        SizeEdgeMapType weights_;
        SettingsType settings_;
    };

    struct RankOrderSettings{
        double q;
        uint16_t numberOfBins;
        RankOrderSettings(double q = 0.5, uint16_t numberOfBins = 50) : q(q), numberOfBins(numberOfBins) { }
        auto name()const{
            std::stringstream ss;
            ss<<"RankOrderEdgeMap [q="<<q<<" #bins="<<numberOfBins<<"]";
            return ss.str();
        }
    };

    template<class G, class T>
    class  RankOrderEdgeMap{
    public:
        static auto staticName(){
            return std::string("RankOrderEdgeMap");
        }
        auto name()const{
            std::stringstream ss;
            ss<<staticName()<<" [q="<<settings_.q<<" #bins="<<settings_.numberOfBins<<"]";
            return ss.str();
        }
        typedef G GraphType;
        typedef nifty::histogram::Histogram<double, double>          HistogramType;
        typedef typename GraphType:: template EdgeMap<HistogramType> HistogramEdgeMapType;
        typedef typename GraphType:: template EdgeMap<T>             SizeEdgeMapType;

        typedef RankOrderSettings SettingsType;

        template<class VALUES, class WEIGHTS>
         RankOrderEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  histogram_(g),
            settings_(settings)
        {
            T minVal =        std::numeric_limits<T>::infinity();
            T maxVal = -1.0 * std::numeric_limits<T>::infinity();

            for(auto edge : g.edges()){

                const auto val = T(values[edge]);
                maxVal = std::max(maxVal, val);
                minVal = std::min(minVal, val);
            }

            for(auto edge : g.edges()){
                auto & hist = histogram_[edge];
                hist.assign(minVal, maxVal, settings_.numberOfBins);
                hist.insert(values[edge], weights[edge]);
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            histogram_[aliveEdge].merge(histogram_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            auto & thist= histogram_[targetEdge];
            const auto &  shist = histogram_[sourceEdge];

            const auto tsum = thist.sum();
            thist = shist;
            thist.normalize(tsum);

        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            histogram_[targetEdge] = histogram_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            auto & hist =  histogram_[targetEdge];
            hist.clearCounts();
            hist.insert(value, weight);
        }

        T operator[](const uint64_t edge)const{
            return histogram_[edge].rank(settings_.q);
        }
    private:
        HistogramEdgeMapType histogram_;
        SettingsType settings_;
    };

    struct MaxSettings{
        auto name()const{
            return std::string("Max");
        }
    };
    template<class G, class T>
    class MaxEdgeMap{
    public:

        static auto staticName(){
            return std::string("Max");
        }
        auto name()const{
            return staticName();
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MaxEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef MaxSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        MaxEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g)
        {
            for(auto edge : g.edges()){
                values_[edge] = values[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            auto & value = values_[aliveEdge];
            value = std::max(value, values_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
        }
        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MaxEdgeMapType values_;
    };

    struct MinSettings{
        auto name()const{
            return std::string("Min");
        }
    };

    template<class G, class T>
    class MinEdgeMap{
    public:

        static auto staticName(){
            return std::string("Min");
        }
        auto name()const{
            return staticName();
        }
        typedef G GraphType;
        typedef typename GraphType:: template EdgeMap<T> MinEdgeMapType;
        typedef typename GraphType:: template EdgeMap<nifty::float16_t> SizeEdgeMapType;

        typedef MinSettings SettingsType;

        template<class VALUES, class WEIGHTS>
        MinEdgeMap(
            const GraphType & g,
            const VALUES & values,
            const WEIGHTS & weights,
            const SettingsType & settings = SettingsType()
        ):  values_(g)
        {
            for(auto edge : g.edges()){
                values_[edge] = values[edge];
            }
        }

        void merge(const uint64_t aliveEdge, const uint64_t deadEdge){
            auto & value = values_[aliveEdge];
            value = std::min(value, values_[deadEdge]);
        }

        void setValueFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void setFrom(const uint64_t targetEdge, const uint64_t sourceEdge){
            values_[targetEdge] = values_[sourceEdge];
        }
        void set(const uint64_t targetEdge, const T & value, const T &  weight){
            values_[targetEdge] = value;
        }
        T operator[](const uint64_t edge)const{
            return values_[edge];
        }
    private:
        MinEdgeMapType values_;
    };

} // merge rule
} // namespace agglo
} // namespace nifty::graph
} // namespace nifty

<|endoftext|>