<commit_before>/**
 * This file is part of the CernVM File System
 *
 * This tool signs a CernVM-FS manifest with an X.509 certificate.
 */

#include "cvmfs_config.h"
#include "swissknife_sign.h"

#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>

#include <cstdio>
#include <cstdlib>
#include <iostream>  // TODO(jblomer): remove
#include <set>
#include <string>
#include <vector>

#include "compression.h"
#include "hash.h"
#include "logging.h"
#include "manifest.h"
#include "signature.h"
#include "smalloc.h"
#include "upload.h"
#include "util.h"

using namespace std;  // NOLINT

int swissknife::CommandSign::Main(const swissknife::ArgumentList &args) {
  string manifest_path = *args.find('m')->second;
  string spooler_definition = *args.find('r')->second;
  string temp_dir = *args.find('t')->second;

  string certificate = "";
  if (args.find('c') != args.end()) certificate = *args.find('c')->second;
  string priv_key = "";
  if (args.find('k') != args.end()) priv_key = *args.find('k')->second;
  string repo_name = "";
  if (args.find('n') != args.end()) repo_name = *args.find('n')->second;
  string pwd = "";
  if (args.find('s') != args.end()) pwd = *args.find('s')->second;
  string meta_info = "";
  if (args.find('M') != args.end()) meta_info = *args.find('M')->second;
  upload::Spooler *spooler = NULL;

  if (!DirectoryExists(temp_dir)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "%s does not exist", temp_dir.c_str());
    return 1;
  }

  signature::SignatureManager signature_manager;
  signature_manager.Init();

  // Load certificate
  unsigned char *cert_buf = NULL;
  unsigned cert_buf_size;
  if (certificate == "") {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "Enter file name of X509 certificate []: ");
    getline(cin, certificate);
  }
  if (!signature_manager.LoadCertificatePath(certificate) ||
      !signature_manager.WriteCertificateMem(&cert_buf, &cert_buf_size))
  {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to load certificate");
    return 2;
  }

  // Load private key
  if (priv_key == "") {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "Enter file name of private key file to your certificate []: ");
    getline(cin, priv_key);
  }
  if (!signature_manager.LoadPrivateKeyPath(priv_key, pwd)) {
    int retry = 0;
    bool success;
    do {
      struct termios defrsett, newrsett;
      char c;
      tcgetattr(fileno(stdin), &defrsett);
      newrsett = defrsett;
      newrsett.c_lflag &= ~ECHO;
      if (tcsetattr(fileno(stdin), TCSAFLUSH, &newrsett) != 0) {
        LogCvmfs(kLogCvmfs, kLogStderr, "terminal failure");
        free(cert_buf);
        return 2;
      }

      LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
               "Enter password for private key: ");
      pwd = "";
      while (cin.get(c) && (c != '\n'))
        pwd += c;
      tcsetattr(fileno(stdin), TCSANOW, &defrsett);
      LogCvmfs(kLogCvmfs, kLogStdout, "");

      success = signature_manager.LoadPrivateKeyPath(priv_key, pwd);
      if (!success) {
        LogCvmfs(kLogCvmfs, kLogStderr, "failed to load private key (%s)",
                 signature_manager.GetCryptoError().c_str());
      }
      retry++;
    } while (!success && (retry < 3));
    if (!success) {
      free(cert_buf);
      return 2;
    }
  }
  if (!signature_manager.KeysMatch()) {
    LogCvmfs(kLogCvmfs, kLogStderr,
             "the private key doesn't seem to match your certificate (%s)",
             signature_manager.GetCryptoError().c_str());
    signature_manager.UnloadPrivateKey();
    free(cert_buf);
    return 2;
  }

  LogCvmfs(kLogCvmfs, kLogStdout, "Signing %s", manifest_path.c_str());
  {
    // Load Manifest
    // TODO(rmeusel): UniquePtr
    manifest::Manifest *manifest = manifest::Manifest::LoadFile(manifest_path);
    if (!manifest) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to parse manifest");
      goto sign_fail;
    }

    // Connect to the spooler
    const upload::SpoolerDefinition sd(spooler_definition,
                                       manifest->GetHashAlgorithm());
    spooler = upload::Spooler::Construct(sd);

    // Register callback for retrieving the certificate hash
    upload::Spooler::CallbackPtr callback =
      spooler->RegisterListener(&CommandSign::CertificateUploadCallback, this);

    // Safe certificate (and wait for the upload through a Future)
    spooler->ProcessCertificate(certificate);
    const shash::Any certificate_hash = certificate_hash_.Get();
    spooler->UnregisterListener(callback);

    if (certificate_hash.IsNull()) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload certificate");
      goto sign_fail;
    }

    // Safe repository meta info file
    shash::Any metainfo_hash;
    if (!meta_info.empty()) {
      upload::Spooler::CallbackPtr callback =
        spooler->RegisterListener(&CommandSign::MetainfoUploadCallback, this);
      spooler->ProcessMetainfo(meta_info);
      metainfo_hash = metainfo_hash_.Get();
      spooler->UnregisterListener(callback);

      if (metainfo_hash.IsNull()) {
        LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info");
        goto sign_fail;
      }
    }

    // Update manifest
    manifest->set_certificate(certificate_hash);
    manifest->set_repository_name(repo_name);
    manifest->set_publish_timestamp(time(NULL));
    if (!metainfo_hash.IsNull())
      manifest->set_meta_info(metainfo_hash);

    string signed_manifest = manifest->ExportString();
    shash::Any published_hash(manifest->GetHashAlgorithm());
    shash::HashMem(
      reinterpret_cast<const unsigned char *>(signed_manifest.data()),
      signed_manifest.length(), &published_hash);
    signed_manifest += "--\n" + published_hash.ToString() + "\n";

    // Create alternative bootstrapping symlinks for VOMS secured repos
    if (manifest->has_alt_catalog_path()) {
      const bool success =
        spooler->PlaceBootstrappingShortcut(manifest->certificate())  &&
        spooler->PlaceBootstrappingShortcut(manifest->catalog_hash()) &&
        (manifest->history().IsNull() ||
         spooler->PlaceBootstrappingShortcut(manifest->history())) &&
        (metainfo_hash.IsNull() ||
         spooler->PlaceBootstrappingShortcut(metainfo_hash));

      if (!success) {
        LogCvmfs(kLogCvmfs, kLogStderr, "failed to place VOMS bootstrapping "
                                        "symlinks");
        delete manifest;
        goto sign_fail;
      }
    }

    // Sign manifest
    unsigned char *sig;
    unsigned sig_size;
    if (!signature_manager.Sign(reinterpret_cast<const unsigned char *>(
                                published_hash.ToString().data()),
                                published_hash.GetHexSize(),
                                &sig, &sig_size))
    {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to sign manifest");
      delete manifest;
      goto sign_fail;
    }

    // Write new manifest
    FILE *fmanifest = fopen(manifest_path.c_str(), "w");
    if (!fmanifest) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to open manifest (errno: %d)",
               errno);
      delete manifest;
      goto sign_fail;
    }
    if ((fwrite(signed_manifest.data(), 1, signed_manifest.length(), fmanifest)
         != signed_manifest.length()) ||
        (fwrite(sig, 1, sig_size, fmanifest) != sig_size))
    {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to write manifest (errno: %d)",
               errno);
      fclose(fmanifest);
      delete manifest;
      goto sign_fail;
    }
    free(sig);
    fclose(fmanifest);

    // Upload manifest
    spooler->Upload(manifest_path, ".cvmfspublished");
    spooler->WaitForUpload();

    unlink(manifest_path.c_str());
    if (spooler->GetNumberOfErrors()) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to commit manifest (errors: %d)",
               spooler->GetNumberOfErrors());
      delete manifest;
      goto sign_fail;
    }

    delete manifest;
  }

  delete spooler;
  signature_manager.Fini();
  return 0;

 sign_fail:
  delete spooler;
  signature_manager.Fini();
  if (cert_buf) free(cert_buf);
  return 1;
}

void swissknife::CommandSign::CertificateUploadCallback(
                                          const upload::SpoolerResult &result) {
  shash::Any certificate_hash;
  if (result.return_code == 0) {
    certificate_hash = result.content_hash;
  } else {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload certificate "
                                    "(retcode: %d)",
                                    result.return_code);
  }
  certificate_hash_.Set(certificate_hash);
}

void swissknife::CommandSign::MetainfoUploadCallback(
                                          const upload::SpoolerResult &result) {
  shash::Any metainfo_hash;
  if (result.return_code == 0) {
    metainfo_hash = result.content_hash;
  } else {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info (retcode: %d)",
             result.return_code);
  }
  metainfo_hash_.Set(metainfo_hash);
}
<commit_msg>Doc: add code smell TODO<commit_after>/**
 * This file is part of the CernVM File System
 *
 * This tool signs a CernVM-FS manifest with an X.509 certificate.
 */

#include "cvmfs_config.h"
#include "swissknife_sign.h"

#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <termios.h>
#include <unistd.h>

#include <cstdio>
#include <cstdlib>
#include <iostream>  // TODO(jblomer): remove
#include <set>
#include <string>
#include <vector>

#include "compression.h"
#include "hash.h"
#include "logging.h"
#include "manifest.h"
#include "signature.h"
#include "smalloc.h"
#include "upload.h"
#include "util.h"

using namespace std;  // NOLINT

int swissknife::CommandSign::Main(const swissknife::ArgumentList &args) {
  string manifest_path = *args.find('m')->second;
  string spooler_definition = *args.find('r')->second;
  string temp_dir = *args.find('t')->second;

  string certificate = "";
  if (args.find('c') != args.end()) certificate = *args.find('c')->second;
  string priv_key = "";
  if (args.find('k') != args.end()) priv_key = *args.find('k')->second;
  string repo_name = "";
  if (args.find('n') != args.end()) repo_name = *args.find('n')->second;
  string pwd = "";
  if (args.find('s') != args.end()) pwd = *args.find('s')->second;
  string meta_info = "";
  if (args.find('M') != args.end()) meta_info = *args.find('M')->second;
  upload::Spooler *spooler = NULL;

  if (!DirectoryExists(temp_dir)) {
    LogCvmfs(kLogCvmfs, kLogStderr, "%s does not exist", temp_dir.c_str());
    return 1;
  }

  signature::SignatureManager signature_manager;
  signature_manager.Init();

  // Load certificate
  unsigned char *cert_buf = NULL;
  unsigned cert_buf_size;
  if (certificate == "") {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "Enter file name of X509 certificate []: ");
    getline(cin, certificate);
  }
  if (!signature_manager.LoadCertificatePath(certificate) ||
      !signature_manager.WriteCertificateMem(&cert_buf, &cert_buf_size))
  {
    LogCvmfs(kLogCvmfs, kLogStderr, "failed to load certificate");
    return 2;
  }

  // Load private key
  // TODO(rmeusel): eliminiate code duplication with swissknife_letter.cc
  if (priv_key == "") {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "Enter file name of private key file to your certificate []: ");
    getline(cin, priv_key);
  }
  if (!signature_manager.LoadPrivateKeyPath(priv_key, pwd)) {
    int retry = 0;
    bool success;
    do {
      struct termios defrsett, newrsett;
      char c;
      tcgetattr(fileno(stdin), &defrsett);
      newrsett = defrsett;
      newrsett.c_lflag &= ~ECHO;
      if (tcsetattr(fileno(stdin), TCSAFLUSH, &newrsett) != 0) {
        LogCvmfs(kLogCvmfs, kLogStderr, "terminal failure");
        free(cert_buf);
        return 2;
      }

      LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
               "Enter password for private key: ");
      pwd = "";
      while (cin.get(c) && (c != '\n'))
        pwd += c;
      tcsetattr(fileno(stdin), TCSANOW, &defrsett);
      LogCvmfs(kLogCvmfs, kLogStdout, "");

      success = signature_manager.LoadPrivateKeyPath(priv_key, pwd);
      if (!success) {
        LogCvmfs(kLogCvmfs, kLogStderr, "failed to load private key (%s)",
                 signature_manager.GetCryptoError().c_str());
      }
      retry++;
    } while (!success && (retry < 3));
    if (!success) {
      free(cert_buf);
      return 2;
    }
  }
  if (!signature_manager.KeysMatch()) {
    LogCvmfs(kLogCvmfs, kLogStderr,
             "the private key doesn't seem to match your certificate (%s)",
             signature_manager.GetCryptoError().c_str());
    signature_manager.UnloadPrivateKey();
    free(cert_buf);
    return 2;
  }

  LogCvmfs(kLogCvmfs, kLogStdout, "Signing %s", manifest_path.c_str());
  {
    // Load Manifest
    // TODO(rmeusel): UniquePtr
    manifest::Manifest *manifest = manifest::Manifest::LoadFile(manifest_path);
    if (!manifest) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to parse manifest");
      goto sign_fail;
    }

    // Connect to the spooler
    const upload::SpoolerDefinition sd(spooler_definition,
                                       manifest->GetHashAlgorithm());
    spooler = upload::Spooler::Construct(sd);

    // Register callback for retrieving the certificate hash
    upload::Spooler::CallbackPtr callback =
      spooler->RegisterListener(&CommandSign::CertificateUploadCallback, this);

    // Safe certificate (and wait for the upload through a Future)
    spooler->ProcessCertificate(certificate);
    const shash::Any certificate_hash = certificate_hash_.Get();
    spooler->UnregisterListener(callback);

    if (certificate_hash.IsNull()) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload certificate");
      goto sign_fail;
    }

    // Safe repository meta info file
    shash::Any metainfo_hash;
    if (!meta_info.empty()) {
      upload::Spooler::CallbackPtr callback =
        spooler->RegisterListener(&CommandSign::MetainfoUploadCallback, this);
      spooler->ProcessMetainfo(meta_info);
      metainfo_hash = metainfo_hash_.Get();
      spooler->UnregisterListener(callback);

      if (metainfo_hash.IsNull()) {
        LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info");
        goto sign_fail;
      }
    }

    // Update manifest
    manifest->set_certificate(certificate_hash);
    manifest->set_repository_name(repo_name);
    manifest->set_publish_timestamp(time(NULL));
    if (!metainfo_hash.IsNull())
      manifest->set_meta_info(metainfo_hash);

    string signed_manifest = manifest->ExportString();
    shash::Any published_hash(manifest->GetHashAlgorithm());
    shash::HashMem(
      reinterpret_cast<const unsigned char *>(signed_manifest.data()),
      signed_manifest.length(), &published_hash);
    signed_manifest += "--\n" + published_hash.ToString() + "\n";

    // Create alternative bootstrapping symlinks for VOMS secured repos
    if (manifest->has_alt_catalog_path()) {
      const bool success =
        spooler->PlaceBootstrappingShortcut(manifest->certificate())  &&
        spooler->PlaceBootstrappingShortcut(manifest->catalog_hash()) &&
        (manifest->history().IsNull() ||
         spooler->PlaceBootstrappingShortcut(manifest->history())) &&
        (metainfo_hash.IsNull() ||
         spooler->PlaceBootstrappingShortcut(metainfo_hash));

      if (!success) {
        LogCvmfs(kLogCvmfs, kLogStderr, "failed to place VOMS bootstrapping "
                                        "symlinks");
        delete manifest;
        goto sign_fail;
      }
    }

    // Sign manifest
    unsigned char *sig;
    unsigned sig_size;
    if (!signature_manager.Sign(reinterpret_cast<const unsigned char *>(
                                published_hash.ToString().data()),
                                published_hash.GetHexSize(),
                                &sig, &sig_size))
    {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to sign manifest");
      delete manifest;
      goto sign_fail;
    }

    // Write new manifest
    FILE *fmanifest = fopen(manifest_path.c_str(), "w");
    if (!fmanifest) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to open manifest (errno: %d)",
               errno);
      delete manifest;
      goto sign_fail;
    }
    if ((fwrite(signed_manifest.data(), 1, signed_manifest.length(), fmanifest)
         != signed_manifest.length()) ||
        (fwrite(sig, 1, sig_size, fmanifest) != sig_size))
    {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to write manifest (errno: %d)",
               errno);
      fclose(fmanifest);
      delete manifest;
      goto sign_fail;
    }
    free(sig);
    fclose(fmanifest);

    // Upload manifest
    spooler->Upload(manifest_path, ".cvmfspublished");
    spooler->WaitForUpload();

    unlink(manifest_path.c_str());
    if (spooler->GetNumberOfErrors()) {
      LogCvmfs(kLogCvmfs, kLogStderr, "Failed to commit manifest (errors: %d)",
               spooler->GetNumberOfErrors());
      delete manifest;
      goto sign_fail;
    }

    delete manifest;
  }

  delete spooler;
  signature_manager.Fini();
  return 0;

 sign_fail:
  delete spooler;
  signature_manager.Fini();
  if (cert_buf) free(cert_buf);
  return 1;
}

void swissknife::CommandSign::CertificateUploadCallback(
                                          const upload::SpoolerResult &result) {
  shash::Any certificate_hash;
  if (result.return_code == 0) {
    certificate_hash = result.content_hash;
  } else {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload certificate "
                                    "(retcode: %d)",
                                    result.return_code);
  }
  certificate_hash_.Set(certificate_hash);
}

void swissknife::CommandSign::MetainfoUploadCallback(
                                          const upload::SpoolerResult &result) {
  shash::Any metainfo_hash;
  if (result.return_code == 0) {
    metainfo_hash = result.content_hash;
  } else {
    LogCvmfs(kLogCvmfs, kLogStderr, "Failed to upload meta info (retcode: %d)",
             result.return_code);
  }
  metainfo_hash_.Set(metainfo_hash);
}
<|endoftext|>


<commit_before>/*
    This program shows how to process BLAS LEVEL2 spr

    for i = 0 .. N
        for j = 0 .. N
            C[i,j] = A[i,j] + alpha * X[i]*X[j]

*/

#include <tiramisu/tiramisu.h>
#define NN 100
#define alpha 3
using namespace tiramisu;

int main(int argc, char **argv)
{
    tiramisu::init("spr");

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------
    constant N("N", NN);
    var i("i", 0, N), j("j", 0, N);
    // Declare inputs : A(Matrix N*N) , X(Vector dim=N)
    input A("A", {i, j}, p_uint8);
    input x("B", {i}, p_uint8);
    // Declare output which is result of computation
    computation output("output", {i,j}, expr((uint8_t)alpha) * x(j) * x(i)  + A(i, j) );

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------
    // Declare the buffers.
    buffer b_A("b_A", {N,N}, p_uint8, a_input);
    buffer b_x("b_x", {N}, p_uint8, a_input);
    buffer b_output("b_output", {N,N}, p_uint8, a_output);
    // Map the computations to a buffer.
    A.store_in(&b_A);
    x.store_in(&b_x);
    output.store_in(&b_output,{i,j});

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------
    tiramisu::codegen({&b_A, &b_x, &b_output}, "build/generated_fct_developers_spr.o");

    return 0;
}
<commit_msg>Update spr.cpp<commit_after>/*
    This program shows how to process BLAS LEVEL2 spr

    for i = 0 .. N
        for j = 0 .. N
            C[i,j] = A[i,j] + alpha * X[i]*X[j]

*/

#include <tiramisu/tiramisu.h>

#define NN 100
#define alpha 3

using namespace tiramisu;

int main(int argc, char **argv)
{
    tiramisu::init("spr");

    // -------------------------------------------------------
    // Layer I
    // -------------------------------------------------------
    constant N("N", NN);
    var i("i", 0, N), j("j", 0, N);

    // Declare inputs : A(Matrix N*N) , X(Vector dim=N)
    input A("A", {i, j}, p_uint8);
    input x("B", {i}, p_uint8);

    // Declare output which is result of computation
    computation output("output", {i,j}, expr((uint8_t)alpha) * x(j) * x(i)  + A(i, j) );

    // -------------------------------------------------------
    // Layer III
    // -------------------------------------------------------
    // Declare the buffers.
    buffer b_A("b_A", {N,N}, p_uint8, a_input);
    buffer b_x("b_x", {N}, p_uint8, a_input);
    buffer b_output("b_output", {N,N}, p_uint8, a_output);

    // Map the computations to a buffer.
    A.store_in(&b_A);
    x.store_in(&b_x);
    output.store_in(&b_output,{i,j});

    // -------------------------------------------------------
    // Code Generation
    // -------------------------------------------------------
    tiramisu::codegen({&b_A, &b_x, &b_output}, "build/generated_fct_developers_spr.o");

    return 0;
}
<|endoftext|>


<commit_before>//===---------------------- SymbolicRangeAnalysis.cpp ---------------------===//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sra"

#include "SymbolicRangeAnalysis.h"

#include "llvm/IR/Constants.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"

raw_ostream& operator<<(raw_ostream& OS, const SymbolicRangeAnalysis& SRR) {
  SRR.print(OS, nullptr);
  return OS;
}

using namespace llvm;

static RegisterPass<SymbolicRangeAnalysis>
  X("sra", "Symbolic range analysis with SAGE and QEPCAD");
char SymbolicRangeAnalysis::ID = 0;

static cl::opt<bool>
    ShouldUseSymBounds("sra-use-sym-bounds", cl::init(false), cl::Hidden,
        cl::desc("Use symbolic mins & maxes for integer bounds"));

static cl::opt<int>
    MaxPhiEvalSize("sra-max-phi-eval-size", cl::init(-1), cl::Hidden,
        cl::desc("Maximum number of operands on phi nodes, phi nodes which"
            "have more will not be evaluated"));

const unsigned CHANGED_LOWER = 1 << 0;
const unsigned CHANGED_UPPER = 1 << 1;

static SAGERange GetBoundsForTy(Type *Ty, SAGEInterface *SI) {
  unsigned Width = Ty->getIntegerBitWidth();
  if (ShouldUseSymBounds) {
    switch (Width) {
      case 8:
        return SAGERange(SAGEExpr(*SI, "CHAR_MIN"), SAGEExpr(*SI, "UCHAR_MAX"));
      case 16:
        return SAGERange(SAGEExpr(*SI, "SHRT_MIN"), SAGEExpr(*SI, "USHRT_MAX"));
      case 32:
        return SAGERange(SAGEExpr(*SI, "INT_MIN"), SAGEExpr(*SI, "UINT_MAX"));
      case 64:
        return SAGERange(SAGEExpr(*SI, "LONG_MIN"), SAGEExpr(*SI, "ULONG_MAX"));
    }
  }
  uint64_t Upper = APInt::getMaxValue(Width).getZExtValue();
  int64_t Lower = APInt::getSignedMinValue(Width).getSExtValue();
  return SAGERange(SAGEExpr(*SI, Lower), SAGEExpr(*SI, Upper));
}

static SAGERange GetBoundsForValue(Value *V, SAGEInterface *SI) {
  return GetBoundsForTy(V->getType(), SI);
}

static SAGERange BinaryOp(BinaryOperator *BO, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: BinaryOp: " << *BO << "\n");

  auto LHS = SRA->getStateOrInf(BO->getOperand(0)),
       RHS = SRA->getStateOrInf(BO->getOperand(1));

  switch (BO->getOpcode()) {
    case Instruction::Add:
      return LHS + RHS;
    case Instruction::Sub:
      return LHS - RHS;
    case Instruction::Mul:
      return LHS * RHS;
    case Instruction::SDiv:
    case Instruction::UDiv:
      return LHS/RHS;
    default:
      return GetBoundsForValue(BO, &SRA->getSI());
  }
}

static SAGERange Narrow(PHINode *Phi, Value *V, ICmpInst::Predicate Pred,
                        SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Narrow: " << *Phi << ", " << *V << "\n");

  auto Ret   = SRA->getStateOrInf(Phi->getIncomingValue(0)),
       Bound = SRA->getState(V);

  std::set<SAGEExpr> Set;
  switch (Pred) {
    case CmpInst::ICMP_SLT:
    case CmpInst::ICMP_ULT:
      Ret.setUpper(Bound.getUpper() - 1);
      break;
    case CmpInst::ICMP_SLE:
    case CmpInst::ICMP_ULE:
      Ret.setUpper(Bound.getUpper());
      break;
    case CmpInst::ICMP_SGT:
    case CmpInst::ICMP_UGT:
      Ret.setLower(Bound.getLower() + 1);
      break;
    case CmpInst::ICMP_SGE:
    case CmpInst::ICMP_UGE:
      Ret.setLower(Bound.getLower());
      break;
    case CmpInst::ICMP_EQ:
      Ret = Bound;
      break;
    default:
      break;
  }
  return Ret;
}

static SAGERange Meet(PHINode *Phi, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Meet: " << *Phi << "\n");

  if (MaxPhiEvalSize > 0 && Phi->getNumOperands() > (unsigned) MaxPhiEvalSize) {
    SAGERange Ret =
        GetBoundsForTy(cast<IntegerType>(Phi->getType()), &SRA->getSI());
    Ret.setLower(Ret.getLower());
    Ret.setUpper(Ret.getUpper());
    return Ret;
  }

  SAGERange Ret = SRA->getState(Phi->getIncomingValue(0));
  auto OI = Phi->op_begin(), OE = Phi->op_end();
  for (; Ret == SRA->getBottom() && OI != OE; ++OI)
    Ret = SRA->getState(*OI);

  for (; OI != OE; ++OI) {
    SAGERange Incoming = SRA->getState(*OI);
    if (Incoming == SRA->getBottom())
      continue;
    Ret.setLower(Ret.getLower().min(Incoming.getLower()));
    Ret.setUpper(Ret.getUpper().max(Incoming.getUpper()));
  }
  return Ret;
}

void SymbolicRangeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<SAGEInterface>();
  AU.addRequired<Redefinition>();
  AU.setPreservesAll();
}

bool SymbolicRangeAnalysis::runOnFunction(Function& F) {
  Module_ = F.getParent();
  SI_ = &getAnalysis<SAGEInterface>();

  dbgs() << "SRA: runOnModule: " << F.getName() << "\n";

  RDF_ = &getAnalysis<Redefinition>();

  initialize(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  widen(&F);

  DEBUG(dbgs() << *this << "\n");

  return false;
}

SAGEExpr SymbolicRangeAnalysis::getBottomExpr() const {
  static SAGEExpr BottomExpr(*SI_, "_BOT_");
  return BottomExpr;
}

SAGERange SymbolicRangeAnalysis::getBottom() const {
  static SAGERange BottomRange(getBottomExpr());
  return BottomRange;
}

std::string SymbolicRangeAnalysis::makeName(Function *F, Value *V) {
  static unsigned Temp = 1;
  if (V->hasName()) {
    auto Name = (F->getName() + Twine("_") + V->getName()).str();
    std::replace(Name.begin(), Name.end(), '.', '_');
    return Name;
  } else {
    auto Name = F->getName() + Twine("_") + Twine(Temp++);
    return Name.str();
  }
}

void SymbolicRangeAnalysis::setName(Value *V, std::string Name) {
  Name_[V] = Name;
  Value_[Name] = V;
}

std::string SymbolicRangeAnalysis::getName(Value *V) const {
  auto It = Name_.find(V);
  assert(It != Name_.end() && "Requested value is not in map");
  return It->second;
}

void SymbolicRangeAnalysis::setState(Value *V, SAGERange Range) {
  DEBUG(dbgs() << "SRA: setState(" << *V << "," << Range << ")\n");
  auto It = State_.insert(std::make_pair(V, Range));
  if (!It.second) {
    if (It.first->second != Range)
      setChanged(V, It.first->second, Range);
    It.first->second = Range;
  } else if (isa<Instruction>(V)) {
    Changed_[V] = CHANGED_LOWER | CHANGED_UPPER;
  }
}

void SymbolicRangeAnalysis::setChanged(Value *V, SAGERange &Prev,
                                       SAGERange &New) {
  Changed_[V] = (Prev.getLower().isNE(New.getLower()) ? CHANGED_LOWER : 0) |
                (Prev.getUpper().isNE(New.getUpper()) ? CHANGED_UPPER : 0);
}

SAGERange SymbolicRangeAnalysis::getState(Value *V) const {
  // TODO: Handle ptrtoint.
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return SAGEExpr(*SI_, CI->getValue().getSExtValue());
  if (isa<UndefValue>(V) || isa<Constant>(V))
    return GetBoundsForValue(V, SI_);
  auto It = State_.find(V);
  assert(It != State_.end() && "Requested value is not in map");
  return It->second;
}

SAGERange SymbolicRangeAnalysis::getStateOrInf(Value *V) const {
  auto State = getState(V);
  return State != getBottom()
      ? State : GetBoundsForTy(cast<IntegerType>(V->getType()), SI_);
}

std::pair<Value*, Value*>
    SymbolicRangeAnalysis::getRangeValuesFor(Value *V, IRBuilder<> IRB) const {
  SAGERange Range = getStateOrInf(V);
  IntegerType *Ty = cast<IntegerType>(V->getType());
  Value *Lower = Range.getLower().toValue(Ty, IRB, Value_, Module_),
        *Upper = Range.getUpper().toValue(Ty, IRB, Value_, Module_);
  return std::make_pair(Lower, Upper);
}

void SymbolicRangeAnalysis::createNarrowingFn(Value *LHS, Value *RHS,
                                      CmpInst::Predicate Pred, BasicBlock *BB) {
  if (auto Redef = RDF_->getRedef(LHS, BB))
    Fn_[Redef] = [Redef, RHS, Pred, this] ()
      { return Narrow(Redef, RHS, Pred, this); };
}

void SymbolicRangeAnalysis::handleBranch(BranchInst *BI, ICmpInst *ICI) {
  Value *LHS = ICI->getOperand(0), *RHS = ICI->getOperand(1);
  BasicBlock *TB = BI->getSuccessor(0), *FB = BI->getSuccessor(1);
  CmpInst::Predicate Pred     = ICI->getPredicate(),
                     SwapPred = ICI->getSwappedPredicate(),
                     InvPred  = ICI->getInversePredicate(), EqPred;

  // For (i < j) branching to cond.true and cond.false, for example:
  // 1) i < j at cond.true;
  createNarrowingFn(LHS, RHS, Pred,     TB);
  // 2) j > i at cond.true;
  createNarrowingFn(RHS, LHS, SwapPred, TB);
  // 3) i >= j at cond.false;
  createNarrowingFn(LHS, RHS, InvPred,  FB);

  if (ICI->isEquality())
    EqPred = Pred;
  else if (ICI->isTrueWhenEqual())
    EqPred = (ICmpInst::Predicate)(Pred - 1);
  else {
    assert(ICI->isFalseWhenEqual());
    EqPred = (ICmpInst::Predicate)(Pred + 1);
  }
  // 4) j <= i at cond.false;
  createNarrowingFn(RHS, LHS, EqPred, FB);
}

void SymbolicRangeAnalysis::handleIntInst(Instruction *I) {
  setName(I,  makeName(I->getParent()->getParent(), I));
  if (isa<LoadInst>(I))
    setState(I, GetBoundsForValue(I, SI_));
  else
    setState(I, getBottom());
  switch (I->getOpcode()) {
    case Instruction::Add:
    case Instruction::Sub:
    case Instruction::Mul:
    case Instruction::SDiv:
    case Instruction::UDiv:
      Fn_[I] = [I, this] ()
        { return BinaryOp(cast<BinaryOperator>(I), this); };
      break;
    case Instruction::PHI:
      if (!Fn_.count(I))
        Fn_[I] = [I, this] ()
          { return Meet(cast<PHINode>(I), this); };
      break;
    case Instruction::Trunc:
    case Instruction::ZExt:
    case Instruction::SExt:
        Fn_[I] = [I, this] ()
          { return this->getState(*I->op_begin()); };
      break;
    default:
      return;
  }
}

void SymbolicRangeAnalysis::initialize(Function *F) {
  // Create symbols for the function's integer arguments.
  for (auto AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
    if (AI->getType()->isIntegerTy()) {
      std::string Name = makeName(F, &(*AI));
      setName(&(*AI), Name);
      SAGEExpr Arg(*SI_, Name.c_str());
      // Range is symbolic - [Arg, Arg].
      setState(&(*AI), SAGERange(Arg));
    }

  // Create a closure for each instruction.
  for (auto &BB : *F) {
    // Handle sigma nodes.
    TerminatorInst *TI = BB.getTerminator();
    if (BranchInst *BI = dyn_cast<BranchInst>(TI))
      if (BI->isConditional())
        if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
          handleBranch(BI, ICI);

    // Handle everything that's not a sigma node.
    for (auto &I : BB)
      if (I.getType()->isIntegerTy()) {
        Mapping_[&I] = Mapping_.size() + 1;
        handleIntInst(&I);
      }
  }
}

void SymbolicRangeAnalysis::reset(Function *F) {
  for (auto &BB : *F)
    for (auto &I : BB)
      if (Changed_.count(&I) && Changed_[&I])
        Worklist_.insert(std::make_pair(Mapping_[&I], &I));

  Evaled_.clear();
  Changed_.clear();
}

void SymbolicRangeAnalysis::iterate(Function *F) {
  DEBUG(dbgs() << "SRA: Iterate\n");
  while (!Worklist_.empty()) {
    auto Next = Worklist_.begin(); Worklist_.erase(Next);
    Instruction *I = Next->second;
    if (Fn_.count(I) && !Evaled_.count(I)) {
      Evaled_.insert(I);
      setState(I, Fn_[I]());
      for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI)
        if (Instruction *Use = dyn_cast<Instruction>(*UI))
          if (!Evaled_.count(Use))
            Worklist_.insert(std::make_pair(Mapping_[Use], Use));
    }
  }
}

void SymbolicRangeAnalysis::widen(Function *F) {
  DEBUG(dbgs() << "SRA: Widen\n");
  for (auto &BB : *F)
    for (auto &I : BB)
      if (I.getType()->isIntegerTy())
        if (Changed_.count(&I) && Changed_[&I]) {
          auto State = getStateOrInf(&I);
          auto Bounds = GetBoundsForValue(&I, SI_);
          if (Changed_[&I] & CHANGED_LOWER)
            State.setLower(Bounds.getLower());
          if (Changed_[&I] & CHANGED_UPPER)
            State.setUpper(Bounds.getUpper());
          setState(&I, State);
        }
}

void SymbolicRangeAnalysis::print(raw_ostream &OS, const Module*) const {
  for (auto P : State_)
    OS << "[[" << getName(P.first) << "]] = " << P.second << "\n";
}

<commit_msg>Add more debug messages to better track evaluation<commit_after>//===---------------------- SymbolicRangeAnalysis.cpp ---------------------===//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "sra"

#include "SymbolicRangeAnalysis.h"

#include "llvm/IR/Constants.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"

raw_ostream& operator<<(raw_ostream& OS, const SymbolicRangeAnalysis& SRR) {
  SRR.print(OS, nullptr);
  return OS;
}

using namespace llvm;

static RegisterPass<SymbolicRangeAnalysis>
  X("sra", "Symbolic range analysis with SAGE and QEPCAD");
char SymbolicRangeAnalysis::ID = 0;

static cl::opt<bool>
    ShouldUseSymBounds("sra-use-sym-bounds", cl::init(false), cl::Hidden,
        cl::desc("Use symbolic mins & maxes for integer bounds"));

static cl::opt<int>
    MaxPhiEvalSize("sra-max-phi-eval-size", cl::init(-1), cl::Hidden,
        cl::desc("Maximum number of operands on phi nodes, phi nodes which"
            "have more will not be evaluated"));

const unsigned CHANGED_LOWER = 1 << 0;
const unsigned CHANGED_UPPER = 1 << 1;

static SAGERange GetBoundsForTy(Type *Ty, SAGEInterface *SI) {
  unsigned Width = Ty->getIntegerBitWidth();
  if (ShouldUseSymBounds) {
    switch (Width) {
      case 8:
        return SAGERange(SAGEExpr(*SI, "CHAR_MIN"), SAGEExpr(*SI, "UCHAR_MAX"));
      case 16:
        return SAGERange(SAGEExpr(*SI, "SHRT_MIN"), SAGEExpr(*SI, "USHRT_MAX"));
      case 32:
        return SAGERange(SAGEExpr(*SI, "INT_MIN"), SAGEExpr(*SI, "UINT_MAX"));
      case 64:
        return SAGERange(SAGEExpr(*SI, "LONG_MIN"), SAGEExpr(*SI, "ULONG_MAX"));
    }
  }
  uint64_t Upper = APInt::getMaxValue(Width).getZExtValue();
  int64_t Lower = APInt::getSignedMinValue(Width).getSExtValue();
  return SAGERange(SAGEExpr(*SI, Lower), SAGEExpr(*SI, Upper));
}

static SAGERange GetBoundsForValue(Value *V, SAGEInterface *SI) {
  return GetBoundsForTy(V->getType(), SI);
}

static SAGERange BinaryOp(BinaryOperator *BO, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: BinaryOp: " << *BO << "\n");

  auto LHS = SRA->getStateOrInf(BO->getOperand(0)),
       RHS = SRA->getStateOrInf(BO->getOperand(1));

  switch (BO->getOpcode()) {
    case Instruction::Add: {
      DEBUG(dbgs() << "     BinaryOp: " << LHS << " + " << RHS << "\n");
      auto Ret = LHS + RHS;
      DEBUG(dbgs() << "     BinaryOp: return " << Ret << "\n");
      return Ret;
    }
    case Instruction::Sub: {
      DEBUG(dbgs() << "     BinaryOp: " << LHS << " - " << RHS << "\n");
      auto Ret = LHS - RHS;
      DEBUG(dbgs() << "     BinaryOp: return " << Ret << "\n");
      return Ret;
    }
    case Instruction::Mul: {
      DEBUG(dbgs() << "     BinaryOp: " << LHS << " * " << RHS << "\n");
      auto Ret = LHS * RHS;
      DEBUG(dbgs() << "     BinaryOp: return " << Ret << "\n");
      return Ret;
    }
    case Instruction::SDiv:
    case Instruction::UDiv: {
      DEBUG(dbgs() << "     BinaryOp: " << LHS << "/" << RHS << "\n");
      auto Ret = LHS/RHS;
      DEBUG(dbgs() << "     BinaryOp: return " << Ret << "\n");
      return Ret;
    }
    default: {
      auto Ret = GetBoundsForValue(BO, &SRA->getSI());
      DEBUG(dbgs() << "     BinaryOp: return " << Ret << "\n");
      return Ret;
    }
  }
}

static SAGERange Narrow(PHINode *Phi, Value *V, ICmpInst::Predicate Pred,
                        SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Narrow: " << *Phi << ", " << *V << "\n");

  auto Ret   = SRA->getStateOrInf(Phi->getIncomingValue(0)),
       Bound = SRA->getState(V);

  std::set<SAGEExpr> Set;
  switch (Pred) {
    case CmpInst::ICMP_SLT:
    case CmpInst::ICMP_ULT:
      DEBUG(dbgs() << "     Narrow: " << Ret << " < " << Bound << "\n");
      Ret.setUpper(Bound.getUpper() - 1);
      break;
    case CmpInst::ICMP_SLE:
    case CmpInst::ICMP_ULE:
      DEBUG(dbgs() << "     Narrow: " << Ret << " <= " << Bound << "\n");
      Ret.setUpper(Bound.getUpper());
      break;
    case CmpInst::ICMP_SGT:
    case CmpInst::ICMP_UGT:
      DEBUG(dbgs() << "     Narrow: " << Ret << " > " << Bound << "\n");
      Ret.setLower(Bound.getLower() + 1);
      break;
    case CmpInst::ICMP_SGE:
    case CmpInst::ICMP_UGE:
      DEBUG(dbgs() << "     Narrow: " << Ret << " >= " << Bound << "\n");
      Ret.setLower(Bound.getLower());
      break;
    case CmpInst::ICMP_EQ:
      DEBUG(dbgs() << "     Narrow: " << Ret << " = " << Bound << "\n");
      Ret = Bound;
      break;
    default:
      break;
  }

  DEBUG(dbgs() << "     Narrow: return " << Ret << "\n");
  return Ret;
}

static SAGERange Meet(PHINode *Phi, SymbolicRangeAnalysis *SRA) {
  DEBUG(dbgs() << "SRA: Meet: " << *Phi << "\n");

  if (MaxPhiEvalSize > 0 && Phi->getNumOperands() > (unsigned) MaxPhiEvalSize) {
    SAGERange Ret =
        GetBoundsForTy(cast<IntegerType>(Phi->getType()), &SRA->getSI());
    Ret.setLower(Ret.getLower());
    Ret.setUpper(Ret.getUpper());
    DEBUG(dbgs() << "     Meet: pruning evaluation\n");
    DEBUG(dbgs() << "     Meet: return " << Ret << "\n");
    return Ret;
  }

  SAGERange Ret = SRA->getState(Phi->getIncomingValue(0));
  auto OI = Phi->op_begin(), OE = Phi->op_end();
  for (; Ret == SRA->getBottom() && OI != OE; ++OI)
    Ret = SRA->getState(*OI);

  DEBUG(dbgs() << "     Meet: starting with " << Ret << "\n");

  for (; OI != OE; ++OI) {
    SAGERange Incoming = SRA->getState(*OI);
    if (Incoming == SRA->getBottom())
      continue;
    Ret.setLower(Ret.getLower().min(Incoming.getLower()));
    Ret.setUpper(Ret.getUpper().max(Incoming.getUpper()));
    DEBUG(dbgs() << "     Meet: meet " << Ret << " and " << Incoming << "\n");
  }

  DEBUG(dbgs() << "     Meet: return " << Ret << "\n");
  return Ret;
}

void SymbolicRangeAnalysis::getAnalysisUsage(AnalysisUsage &AU) const {
  AU.addRequired<SAGEInterface>();
  AU.addRequired<Redefinition>();
  AU.setPreservesAll();
}

bool SymbolicRangeAnalysis::runOnFunction(Function& F) {
  Module_ = F.getParent();
  SI_ = &getAnalysis<SAGEInterface>();

  dbgs() << "SRA: runOnModule: " << F.getName() << "\n";

  RDF_ = &getAnalysis<Redefinition>();

  initialize(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  reset(&F);
  iterate(&F);
  widen(&F);

  DEBUG(dbgs() << *this << "\n");

  return false;
}

SAGEExpr SymbolicRangeAnalysis::getBottomExpr() const {
  static SAGEExpr BottomExpr(*SI_, "_BOT_");
  return BottomExpr;
}

SAGERange SymbolicRangeAnalysis::getBottom() const {
  static SAGERange BottomRange(getBottomExpr());
  return BottomRange;
}

std::string SymbolicRangeAnalysis::makeName(Function *F, Value *V) {
  static unsigned Temp = 1;
  if (V->hasName()) {
    auto Name = (F->getName() + Twine("_") + V->getName()).str();
    std::replace(Name.begin(), Name.end(), '.', '_');
    return Name;
  } else {
    auto Name = F->getName() + Twine("_") + Twine(Temp++);
    return Name.str();
  }
}

void SymbolicRangeAnalysis::setName(Value *V, std::string Name) {
  Name_[V] = Name;
  Value_[Name] = V;
}

std::string SymbolicRangeAnalysis::getName(Value *V) const {
  auto It = Name_.find(V);
  assert(It != Name_.end() && "Requested value is not in map");
  return It->second;
}

void SymbolicRangeAnalysis::setState(Value *V, SAGERange Range) {
  DEBUG(dbgs() << "SRA: setState(" << *V << "," << Range << ")\n");
  auto It = State_.insert(std::make_pair(V, Range));
  if (!It.second) {
    if (It.first->second != Range)
      setChanged(V, It.first->second, Range);
    It.first->second = Range;
  } else if (isa<Instruction>(V)) {
    Changed_[V] = CHANGED_LOWER | CHANGED_UPPER;
  }
}

void SymbolicRangeAnalysis::setChanged(Value *V, SAGERange &Prev,
                                       SAGERange &New) {
  Changed_[V] = (Prev.getLower().isNE(New.getLower()) ? CHANGED_LOWER : 0) |
                (Prev.getUpper().isNE(New.getUpper()) ? CHANGED_UPPER : 0);
}

SAGERange SymbolicRangeAnalysis::getState(Value *V) const {
  // TODO: Handle ptrtoint.
  if (ConstantInt *CI = dyn_cast<ConstantInt>(V))
    return SAGEExpr(*SI_, CI->getValue().getSExtValue());
  if (isa<UndefValue>(V) || isa<Constant>(V))
    return GetBoundsForValue(V, SI_);
  auto It = State_.find(V);
  assert(It != State_.end() && "Requested value is not in map");
  return It->second;
}

SAGERange SymbolicRangeAnalysis::getStateOrInf(Value *V) const {
  auto State = getState(V);
  return State != getBottom()
      ? State : GetBoundsForTy(cast<IntegerType>(V->getType()), SI_);
}

std::pair<Value*, Value*>
    SymbolicRangeAnalysis::getRangeValuesFor(Value *V, IRBuilder<> IRB) const {
  SAGERange Range = getStateOrInf(V);
  IntegerType *Ty = cast<IntegerType>(V->getType());
  Value *Lower = Range.getLower().toValue(Ty, IRB, Value_, Module_),
        *Upper = Range.getUpper().toValue(Ty, IRB, Value_, Module_);
  return std::make_pair(Lower, Upper);
}

void SymbolicRangeAnalysis::createNarrowingFn(Value *LHS, Value *RHS,
                                      CmpInst::Predicate Pred, BasicBlock *BB) {
  if (auto Redef = RDF_->getRedef(LHS, BB))
    Fn_[Redef] = [Redef, RHS, Pred, this] ()
      { return Narrow(Redef, RHS, Pred, this); };
}

void SymbolicRangeAnalysis::handleBranch(BranchInst *BI, ICmpInst *ICI) {
  Value *LHS = ICI->getOperand(0), *RHS = ICI->getOperand(1);
  BasicBlock *TB = BI->getSuccessor(0), *FB = BI->getSuccessor(1);
  CmpInst::Predicate Pred     = ICI->getPredicate(),
                     SwapPred = ICI->getSwappedPredicate(),
                     InvPred  = ICI->getInversePredicate(), EqPred;

  // For (i < j) branching to cond.true and cond.false, for example:
  // 1) i < j at cond.true;
  createNarrowingFn(LHS, RHS, Pred,     TB);
  // 2) j > i at cond.true;
  createNarrowingFn(RHS, LHS, SwapPred, TB);
  // 3) i >= j at cond.false;
  createNarrowingFn(LHS, RHS, InvPred,  FB);

  if (ICI->isEquality())
    EqPred = Pred;
  else if (ICI->isTrueWhenEqual())
    EqPred = (ICmpInst::Predicate)(Pred - 1);
  else {
    assert(ICI->isFalseWhenEqual());
    EqPred = (ICmpInst::Predicate)(Pred + 1);
  }
  // 4) j <= i at cond.false;
  createNarrowingFn(RHS, LHS, EqPred, FB);
}

void SymbolicRangeAnalysis::handleIntInst(Instruction *I) {
  setName(I,  makeName(I->getParent()->getParent(), I));
  if (isa<LoadInst>(I))
    setState(I, GetBoundsForValue(I, SI_));
  else
    setState(I, getBottom());
  switch (I->getOpcode()) {
    case Instruction::Add:
    case Instruction::Sub:
    case Instruction::Mul:
    case Instruction::SDiv:
    case Instruction::UDiv:
      Fn_[I] = [I, this] ()
        { return BinaryOp(cast<BinaryOperator>(I), this); };
      break;
    case Instruction::PHI:
      if (!Fn_.count(I))
        Fn_[I] = [I, this] ()
          { return Meet(cast<PHINode>(I), this); };
      break;
    case Instruction::Trunc:
    case Instruction::ZExt:
    case Instruction::SExt:
        Fn_[I] = [I, this] ()
          { return this->getState(*I->op_begin()); };
      break;
    default:
      return;
  }
}

void SymbolicRangeAnalysis::initialize(Function *F) {
  // Create symbols for the function's integer arguments.
  for (auto AI = F->arg_begin(), AE = F->arg_end(); AI != AE; ++AI)
    if (AI->getType()->isIntegerTy()) {
      std::string Name = makeName(F, &(*AI));
      setName(&(*AI), Name);
      SAGEExpr Arg(*SI_, Name.c_str());
      // Range is symbolic - [Arg, Arg].
      setState(&(*AI), SAGERange(Arg));
    }

  // Create a closure for each instruction.
  for (auto &BB : *F) {
    // Handle sigma nodes.
    TerminatorInst *TI = BB.getTerminator();
    if (BranchInst *BI = dyn_cast<BranchInst>(TI))
      if (BI->isConditional())
        if (ICmpInst *ICI = dyn_cast<ICmpInst>(BI->getCondition()))
          handleBranch(BI, ICI);

    // Handle everything that's not a sigma node.
    for (auto &I : BB)
      if (I.getType()->isIntegerTy()) {
        Mapping_[&I] = Mapping_.size() + 1;
        handleIntInst(&I);
      }
  }
}

void SymbolicRangeAnalysis::reset(Function *F) {
  for (auto &BB : *F)
    for (auto &I : BB)
      if (Changed_.count(&I) && Changed_[&I])
        Worklist_.insert(std::make_pair(Mapping_[&I], &I));

  Evaled_.clear();
  Changed_.clear();
}

void SymbolicRangeAnalysis::iterate(Function *F) {
  DEBUG(dbgs() << "SRA: Iterate\n");
  while (!Worklist_.empty()) {
    auto Next = Worklist_.begin(); Worklist_.erase(Next);
    Instruction *I = Next->second;
    if (Fn_.count(I) && !Evaled_.count(I)) {
      Evaled_.insert(I);
      setState(I, Fn_[I]());
      for (auto UI = I->use_begin(), UE = I->use_end(); UI != UE; ++UI)
        if (Instruction *Use = dyn_cast<Instruction>(*UI))
          if (!Evaled_.count(Use))
            Worklist_.insert(std::make_pair(Mapping_[Use], Use));
    }
  }
}

void SymbolicRangeAnalysis::widen(Function *F) {
  DEBUG(dbgs() << "SRA: Widen\n");
  for (auto &BB : *F)
    for (auto &I : BB)
      if (I.getType()->isIntegerTy())
        if (Changed_.count(&I) && Changed_[&I]) {
          auto State = getStateOrInf(&I);
          auto Bounds = GetBoundsForValue(&I, SI_);
          if (Changed_[&I] & CHANGED_LOWER)
            State.setLower(Bounds.getLower());
          if (Changed_[&I] & CHANGED_UPPER)
            State.setUpper(Bounds.getUpper());
          setState(&I, State);
        }
}

void SymbolicRangeAnalysis::print(raw_ostream &OS, const Module*) const {
  for (auto P : State_)
    OS << "[[" << getName(P.first) << "]] = " << P.second << "\n";
}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <Module.h>
#include <processor/types.h>
#include <machine/Machine.h>
#include <machine/Device.h>
#include <machine/Bus.h>
#include <processor/IoPort.h>
#include <utilities/utility.h>
#include <machine/Pci.h>
#include "pci_list.h"

#define CONFIG_ADDRESS 0
#define CONFIG_DATA    4

#define MAX_BUS 4

IoPort configSpace("PCI config space");

union ConfigAddress {
  struct
  {
    uint32_t always0  : 2;
    uint32_t offset   : 6;
    uint32_t function : 3;
    uint32_t device   : 5;
    uint32_t bus      : 8;
    uint32_t reserved : 7;
    uint32_t enable   : 1;
  } __attribute__((packed));
  uint32_t raw;
};

struct ConfigSpace
{
  uint16_t vendor;
  uint16_t device;
  uint16_t command;
  uint16_t status;
  uint8_t  revision;
  uint8_t  progif;
  uint8_t  subclass;
  uint8_t  class_code;
  uint8_t  cache_line_size;
  uint8_t  latency_timer;
  uint8_t  header_type;
  uint8_t  bist;
  uint32_t bar[6];
  uint32_t cardbus_pointer;
  uint16_t subsys_vendor;
  uint16_t subsys_id;
  uint32_t rom_base_address;
  uint32_t reserved0;
  uint32_t reserved1;
  uint8_t  interrupt_line;
  uint8_t  interrupt_pin;
  uint8_t  min_grant;
  uint8_t  max_latency;
} __attribute__((packed));

void readConfigSpace (Device *pDev, ConfigSpace *pCs)
{
  uint32_t *pCs32 = reinterpret_cast<uint32_t*> (pCs);
  for (unsigned int i = 0; i < sizeof(ConfigSpace)/4; i++)
  {
    pCs32[i] = PciBus::instance().readConfigSpace(pDev, i);
  }
}

const char *getVendor (uint16_t vendor)
{
  for (unsigned int i = 0; i < PCI_VENTABLE_LEN; i++)
  {
    if (PciVenTable[i].VenId == vendor)
      return PciVenTable[i].VenShort;
  }
  return "";
}

const char *getDevice (uint16_t vendor, uint16_t device)
{
  for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; i++)
  {
    if (PciDevTable[i].VenId == vendor && PciDevTable[i].DevId == device)
      return PciDevTable[i].ChipDesc;
  }
  return "";
}

void entry()
{
  for (int iBus = 0; iBus < MAX_BUS; iBus++)
  {
    // Firstly add the ISA bus.
    char *str = new char[256];
    sprintf(str, "PCI #%d", iBus);
    Bus *pBus = new Bus(str);
    pBus->setSpecificType(String("pci"));

    for (int iDevice = 0; iDevice < 32; iDevice++)
    {
      bool bIsMultifunc = false;
      for (int iFunc = 0; iFunc < 8; iFunc++)
      {
        if (iFunc > 0 && !bIsMultifunc)
            break;

        Device *pDevice = new Device();
        pDevice->setPciPosition(iBus, iDevice, iFunc);

        uint32_t vendorAndDeviceId = PciBus::instance().readConfigSpace(pDevice, 0);
        if ( (vendorAndDeviceId & 0xFFFF) == 0xFFFF || (vendorAndDeviceId & 0xFFFF) == 0 )
        {
          delete pDevice;
          break;
        }

        ConfigSpace cs;
        readConfigSpace(pDevice, &cs);

        if (cs.header_type & 0x80)
            bIsMultifunc = true;

        NOTICE("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc << "\t Vendor:" << Hex << cs.vendor << " Device:" << cs.device);

        char c[256];
        sprintf(c, "%s - %s", getDevice(cs.vendor, cs.device), getVendor(cs.vendor));
        pDevice->setSpecificType(String(c));
        pDevice->setPciIdentifiers(cs.class_code, cs.subclass, cs.vendor, cs.device, cs.progif);

        for (int l = 0; l < 6; l++)
        {
            // PCI-PCI bridges have a different layout for the last 4 BARs: they hold extra data.
            if ((cs.header_type&0x7F) == 0x1 && l >= 2)
            {
                break;
            }

          if (cs.bar[l] == 0) continue;

          // Write the BAR with FFFFFFFF to discover the size of mapping that the device requires.
          ConfigAddress ca2;

          uint8_t offset = (0x10 + l*4) >> 2;
          PciBus::instance().writeConfigSpace(pDevice, offset, 0xFFFFFFFF);
          uint32_t mask = PciBus::instance().readConfigSpace(pDevice, offset);
          PciBus::instance().writeConfigSpace(pDevice, offset, cs.bar[l]);

          // Now work out how much space is required to fill that mask.
          // Assume it doesn't need 4GB of space...
          uint32_t size = ~(mask&0xFFFFFFF0) + 1; // AND with ~0xF to get rid of the flags field in the bottom 4 bits.

          bool io = (cs.bar[l] & 0x1);
          if (io)
              // IO space is only 64K in size.
              size &= 0xFFFF;

          sprintf(c, "bar%d", l);
          uintptr_t s = (cs.bar[l]&0xFFFFFFF0);

          NOTICE("PCI:     BAR" << Dec << l << Hex << ": " << s << ".." << (s + size) << " (" << io << ")");
          Device::Address *pAddress = new Device::Address(String(c), cs.bar[l]&0xFFFFFFF0, size, (cs.bar[l]&0x1) == 0x1);
          pDevice->addresses().pushBack(pAddress);
        }

        pDevice->setInterruptNumber(cs.interrupt_line);
        pBus->addChild(pDevice);
        pDevice->setParent(pBus);
      }
    }

    // If the bus was actually populated...
    if (pBus->getNumChildren() > 0)
    {
      Device::root().addChild(pBus);
      pBus->setParent(&Device::root());
    }
    else
    {
      delete pBus;
    }
  }
}

void exit()
{
}

MODULE_NAME("pci");
MODULE_ENTRY(&entry);
MODULE_EXIT(&exit);
MODULE_DEPENDS(0);

<commit_msg>Fixed PCI, so it won't skip any functions on realHW.<commit_after>/*
 * Copyright (c) 2008 James Molloy, Jörg Pfähler, Matthew Iselin
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <Log.h>
#include <Module.h>
#include <processor/types.h>
#include <machine/Machine.h>
#include <machine/Device.h>
#include <machine/Bus.h>
#include <processor/IoPort.h>
#include <utilities/utility.h>
#include <machine/Pci.h>
#include "pci_list.h"

#define CONFIG_ADDRESS 0
#define CONFIG_DATA    4

#define MAX_BUS 4

IoPort configSpace("PCI config space");

union ConfigAddress {
  struct
  {
    uint32_t always0  : 2;
    uint32_t offset   : 6;
    uint32_t function : 3;
    uint32_t device   : 5;
    uint32_t bus      : 8;
    uint32_t reserved : 7;
    uint32_t enable   : 1;
  } __attribute__((packed));
  uint32_t raw;
};

struct ConfigSpace
{
  uint16_t vendor;
  uint16_t device;
  uint16_t command;
  uint16_t status;
  uint8_t  revision;
  uint8_t  progif;
  uint8_t  subclass;
  uint8_t  class_code;
  uint8_t  cache_line_size;
  uint8_t  latency_timer;
  uint8_t  header_type;
  uint8_t  bist;
  uint32_t bar[6];
  uint32_t cardbus_pointer;
  uint16_t subsys_vendor;
  uint16_t subsys_id;
  uint32_t rom_base_address;
  uint32_t reserved0;
  uint32_t reserved1;
  uint8_t  interrupt_line;
  uint8_t  interrupt_pin;
  uint8_t  min_grant;
  uint8_t  max_latency;
} __attribute__((packed));

void readConfigSpace (Device *pDev, ConfigSpace *pCs)
{
  uint32_t *pCs32 = reinterpret_cast<uint32_t*> (pCs);
  for (unsigned int i = 0; i < sizeof(ConfigSpace)/4; i++)
  {
    pCs32[i] = PciBus::instance().readConfigSpace(pDev, i);
  }
}

const char *getVendor (uint16_t vendor)
{
  for (unsigned int i = 0; i < PCI_VENTABLE_LEN; i++)
  {
    if (PciVenTable[i].VenId == vendor)
      return PciVenTable[i].VenShort;
  }
  return "";
}

const char *getDevice (uint16_t vendor, uint16_t device)
{
  for (unsigned int i = 0; i < PCI_DEVTABLE_LEN; i++)
  {
    if (PciDevTable[i].VenId == vendor && PciDevTable[i].DevId == device)
      return PciDevTable[i].ChipDesc;
  }
  return "";
}

void entry()
{
  for (int iBus = 0; iBus < MAX_BUS; iBus++)
  {
    // Firstly add the ISA bus.
    char *str = new char[256];
    sprintf(str, "PCI #%d", iBus);
    Bus *pBus = new Bus(str);
    pBus->setSpecificType(String("pci"));

    for (int iDevice = 0; iDevice < 32; iDevice++)
    {
      bool bIsMultifunc = false;
      for (int iFunc = 0; iFunc < 8; iFunc++)
      {
        if (iFunc > 0 && !bIsMultifunc)
            break;

        Device *pDevice = new Device();
        pDevice->setPciPosition(iBus, iDevice, iFunc);

        uint32_t vendorAndDeviceId = PciBus::instance().readConfigSpace(pDevice, 0);
        if ( (vendorAndDeviceId & 0xFFFF) == 0xFFFF || (vendorAndDeviceId & 0xFFFF) == 0 )
        {
          delete pDevice;
          /// \note In some cases there are gaps between functions,
          /// so it shouldn't just skip the rest of the functions
          /// left of the current device. eddyb
          continue;
          // break;
        }

        ConfigSpace cs;
        readConfigSpace(pDevice, &cs);

        if (cs.header_type & 0x80)
            bIsMultifunc = true;

        NOTICE("PCI: " << Dec << iBus << ":" << iDevice << ":" << iFunc << "\t Vendor:" << Hex << cs.vendor << " Device:" << cs.device);

        char c[256];
        sprintf(c, "%s - %s", getDevice(cs.vendor, cs.device), getVendor(cs.vendor));
        pDevice->setSpecificType(String(c));
        pDevice->setPciIdentifiers(cs.class_code, cs.subclass, cs.vendor, cs.device, cs.progif);

        for (int l = 0; l < 6; l++)
        {
            // PCI-PCI bridges have a different layout for the last 4 BARs: they hold extra data.
            if ((cs.header_type&0x7F) == 0x1 && l >= 2)
            {
                break;
            }

          if (cs.bar[l] == 0) continue;

          // Write the BAR with FFFFFFFF to discover the size of mapping that the device requires.
          ConfigAddress ca2;

          uint8_t offset = (0x10 + l*4) >> 2;
          PciBus::instance().writeConfigSpace(pDevice, offset, 0xFFFFFFFF);
          uint32_t mask = PciBus::instance().readConfigSpace(pDevice, offset);
          PciBus::instance().writeConfigSpace(pDevice, offset, cs.bar[l]);

          // Now work out how much space is required to fill that mask.
          // Assume it doesn't need 4GB of space...
          uint32_t size = ~(mask&0xFFFFFFF0) + 1; // AND with ~0xF to get rid of the flags field in the bottom 4 bits.

          bool io = (cs.bar[l] & 0x1);
          if (io)
              // IO space is only 64K in size.
              size &= 0xFFFF;

          sprintf(c, "bar%d", l);
          uintptr_t s = (cs.bar[l]&0xFFFFFFF0);

          NOTICE("PCI:     BAR" << Dec << l << Hex << ": " << s << ".." << (s + size) << " (" << io << ")");
          Device::Address *pAddress = new Device::Address(String(c), cs.bar[l]&0xFFFFFFF0, size, (cs.bar[l]&0x1) == 0x1);
          pDevice->addresses().pushBack(pAddress);
        }

        pDevice->setInterruptNumber(cs.interrupt_line);
        pBus->addChild(pDevice);
        pDevice->setParent(pBus);
      }
    }

    // If the bus was actually populated...
    if (pBus->getNumChildren() > 0)
    {
      Device::root().addChild(pBus);
      pBus->setParent(&Device::root());
    }
    else
    {
      delete pBus;
    }
  }
}

void exit()
{
}

MODULE_NAME("pci");
MODULE_ENTRY(&entry);
MODULE_EXIT(&exit);
MODULE_DEPENDS(0);

<|endoftext|>


<commit_before>// $Id$
//
// Copyright (C) 2008 Greg Landrum
// All Rights Reserved
//

#include <string>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>
#include <GraphMol/Substruct/SubstructMatch.h>

#include "RDKFuncs.h"

using namespace RDKit;
ROMol *MolFromSmiles(std::string smi) {
  return SmilesToMol(smi);
};
ROMol *MolFromSmarts(std::string sma) {
  return SmartsToMol(sma);
};
std::string MolToSmiles(ROMol *mol,bool doIsomericSmiles,
                        bool doKekule, int rootedAtAtom) {
  return MolToSmiles(*mol,doIsomericSmiles,doKekule,rootedAtAtom);
};
bool HasSubstructMatch(ROMol &mol,ROMol &query,bool useChirality,
                       bool registerQuery){
  MatchVectType mv;
  return SubstructMatch(mol,query,mv,true,useChirality,registerQuery);
};
#if 0
MatchVectType GetSubstructMatches(ROMol &mol,ROMol &query,bool useChirality,
                                  bool registerQuery){
  MatchVectType mv;
  return SubstructMatch(mol,query,mv,true,useChirality,registerQuery);
};
#endif
std::string PickleMol(RDKit::ROMol *mol){
  std::string res="";
  RDKit::MolPickler::pickleMol(mol,res);
  return res;
}
RDKit::ROMol *MolFromPickle(std::string pkl){
  RDKit::ROMol *res=new RDKit::ROMol(pkl);
  return res;
}

<commit_msg>update for molpickler changes<commit_after>// $Id$
//
// Copyright (C) 2008 Greg Landrum
// All Rights Reserved
//

#include <string>
#include <GraphMol/RDKitBase.h>
#include <GraphMol/MolPickler.h>
#include <GraphMol/SmilesParse/SmilesParse.h>
#include <GraphMol/SmilesParse/SmilesWrite.h>
#include <GraphMol/Substruct/SubstructMatch.h>

#include "RDKFuncs.h"

using namespace RDKit;
ROMol *MolFromSmiles(std::string smi) {
  return SmilesToMol(smi);
};
ROMol *MolFromSmarts(std::string sma) {
  return SmartsToMol(sma);
};
std::string MolToSmiles(ROMol *mol,bool doIsomericSmiles,
                        bool doKekule, int rootedAtAtom) {
  return MolToSmiles(*mol,doIsomericSmiles,doKekule,rootedAtAtom);
};
bool HasSubstructMatch(ROMol &mol,ROMol &query,bool useChirality,
                       bool registerQuery){
  MatchVectType mv;
  return SubstructMatch(mol,query,mv,true,useChirality,registerQuery);
};
#if 0
MatchVectType GetSubstructMatches(ROMol &mol,ROMol &query,bool useChirality,
                                  bool registerQuery){
  MatchVectType mv;
  return SubstructMatch(mol,query,mv,true,useChirality,registerQuery);
};
#endif
std::string PickleMol(RDKit::ROMol *mol){
  std::string res="";
  RDKit::MolPickler::pickleMol(mol,res);
  return res;
}
RDKit::ROMol *MolFromPickle(std::string pkl){
  RDKit::ROMol *res=new RDKit::ROMol(pkl);
  return res;
}

<|endoftext|>


<commit_before>#include "kernel.h"
#include "raster.h"
#include "gridcoverage.h"
#include "pixeliterator.h"
#include "connectorinterface.h"
#include "symboltable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "numericitem.h"
#include "numericitemrange.h"
#include "ilwisoperation.h"

quint64 Ilwis::GridBlockInternal::_blockid = 0;

using namespace Ilwis;

GridCoverage::GridCoverage()
{
}

GridCoverage::GridCoverage(const Resource& res) : Coverage(res){

}

GridCoverage::~GridCoverage()
{
}

const IGeoReference& GridCoverage::georeference() const
{
    return _georef;
}

void GridCoverage::georeference(const IGeoReference &grf)
{
    _georef = grf;
    if ( _grid.isNull() == false) { // remove the current grid, all has become uncertain
        _grid.reset(0);

    }
    if ( _georef.isValid()) {
        _georef->compute();
        setCoordinateSystem(grf->coordinateSystem()); // mandatory
    }
}

IlwisTypes GridCoverage::ilwisType() const
{
    return itGRID;
}

GridCoverage *GridCoverage::copy()
{
    GridCoverage *gc = new GridCoverage();
    copyTo(gc);
    return gc;

}

void GridCoverage::copyBinary(const IGridCoverage& gc, int index) {
    IGridCoverage gcNew;
    gcNew.set(this);
    Size inputSize =  gc->size();
    Size sz(inputSize.xsize(),inputSize.ysize(), 1);
    gcNew->georeference()->size(sz);
    PixelIterator iterIn(gc, Box3D<>(Voxel(0,0,index), Voxel(inputSize.xsize(), inputSize.ysize(), index + 1)));
    PixelIterator iterOut(gcNew, Box3D<>(Size(inputSize.xsize(), inputSize.ysize(), 1)));
    for_each(iterOut, iterOut.end(), [&](double& v){
         v = *iterIn;
        ++iterIn;
    });
}

IGridCoverage GridCoverage::get(quint32 index1, quint32 index2)
{
    IGridCoverage gcovParent;
    gcovParent.set(this);
    IGridCoverage gcov = OperationHelperRaster::initialize(gcovParent,itGRID, itDOMAIN | itCOORDSYSTEM | itGEOREF);
    gcov->size(Size(size().xsize(), size().ysize()));
    gcov->_grid.reset(gcov->_grid->clone(index1, index2));

    return gcov;

}

IGridCoverage GridCoverage::get(const QString &item1, const QString &item2)
{
    IDomain indexDomain = datadef().domain(DataDefinition::daINDEX);
    if (!indexDomain.isValid())
        return IGridCoverage();
    if ( indexDomain->valueType() == itNUMERICITEM)  {
        double item1Index = item1.toDouble();
        INumericItemDomain numdom = indexDomain.get<NumericItemDomain>();
        SPNumericItemRange numrange = numdom->range<NumericItemRange>();
        double index1 = numrange->index(item1Index);
        double rest1 = index1 - (int)index1;
        if ( std::abs(rest1) > EPS8 && numrange->isContinous()) {
            int lowerIndex = std::floor(index1);
            double rest2 = 1.0 - rest1;
            QString expr = numrange->interpolation();
            QString nm = name();
            int ind = 0;
            if( (ind=nm.lastIndexOf(".")) != -1){
                nm = nm.left(ind);
            }
            nm = QString("%1_%2_%3").arg(nm).arg(lowerIndex).arg(lowerIndex+1);
            expr = nm + "=" + expr.arg(QString("%1*%2[%3]").arg(rest2).arg(name()).arg(lowerIndex)).arg(QString("%1*%2[%3]").arg(rest1).arg(name()).arg(lowerIndex+1));
            IGridCoverage mp = Operation::calculate<IGridCoverage>(nm,expr);
            if ( mp.isValid())
                return mp;
        }
    }
    return IGridCoverage();
}

Grid *GridCoverage::grid()
{
    Locker lock(_mutex);
    if ( _georef->isValid() && !connector().isNull()) {
        if ( _grid.isNull()) {
            _grid.reset(connector()->loadGridData(this));
            if (_grid.isNull())
                return 0;
        }
        Grid *grd = _grid.data();
        return grd;
    }
    return 0;
}

void GridCoverage::copyTo(IlwisObject *obj)
{
    Locker lock(_mutex);
    Coverage::copyTo(obj);
    GridCoverage *gc = static_cast<GridCoverage *>(obj);
    gc->_georef = _georef;
    if ( _grid) {
        gc->_grid.reset(_grid->clone());
    }

}

Resource GridCoverage::resource(int mode) const
{
    Resource res = Coverage::resource(mode);
    if ( mode & IlwisObject::cmEXTENDED) {
        res["georeference()"] = georeference()->id();
        res.setExtendedType( res.extendedType() | itGEOREF);
    }
    return res;
}

Size GridCoverage::size() const
{
    if (_size.isValid() && !_size.isNull())
        return _size;
    if (!_grid.isNull())
        const_cast<GridCoverage *>(this)->_size = _grid->size();
    else if ( _georef.isValid())
        const_cast<GridCoverage *>(this)->_size = _georef->size();

    return _size;

}

void GridCoverage::size(const Size &sz)
{
    // size must always be positive or undefined
    if (sz.xsize() > 0 && sz.ysize() > 0) {
        _size = sz;
        if (!_grid.isNull())
            _grid->setSize(sz);
        if (_georef.isValid())
            _georef->size(sz);
    }

}

<commit_msg>adapted the get method for non-continuous sub indexing<commit_after>#include "kernel.h"
#include "raster.h"
#include "gridcoverage.h"
#include "pixeliterator.h"
#include "connectorinterface.h"
#include "symboltable.h"
#include "domainitem.h"
#include "itemdomain.h"
#include "numericitem.h"
#include "numericitemrange.h"
#include "ilwisoperation.h"

quint64 Ilwis::GridBlockInternal::_blockid = 0;

using namespace Ilwis;

GridCoverage::GridCoverage()
{
}

GridCoverage::GridCoverage(const Resource& res) : Coverage(res){

}

GridCoverage::~GridCoverage()
{
}

const IGeoReference& GridCoverage::georeference() const
{
    return _georef;
}

void GridCoverage::georeference(const IGeoReference &grf)
{
    _georef = grf;
    if ( _grid.isNull() == false) { // remove the current grid, all has become uncertain
        _grid.reset(0);

    }
    if ( _georef.isValid()) {
        _georef->compute();
        setCoordinateSystem(grf->coordinateSystem()); // mandatory
    }
}

IlwisTypes GridCoverage::ilwisType() const
{
    return itGRID;
}

GridCoverage *GridCoverage::copy()
{
    GridCoverage *gc = new GridCoverage();
    copyTo(gc);
    return gc;

}

void GridCoverage::copyBinary(const IGridCoverage& gc, int index) {
    IGridCoverage gcNew;
    gcNew.set(this);
    Size inputSize =  gc->size();
    Size sz(inputSize.xsize(),inputSize.ysize(), 1);
    gcNew->georeference()->size(sz);
    PixelIterator iterIn(gc, Box3D<>(Voxel(0,0,index), Voxel(inputSize.xsize(), inputSize.ysize(), index + 1)));
    PixelIterator iterOut(gcNew, Box3D<>(Size(inputSize.xsize(), inputSize.ysize(), 1)));
    for_each(iterOut, iterOut.end(), [&](double& v){
         v = *iterIn;
        ++iterIn;
    });
}

IGridCoverage GridCoverage::get(quint32 index1, quint32 index2)
{
    IGridCoverage gcovParent;
    gcovParent.set(this);
    IGridCoverage gcov = OperationHelperRaster::initialize(gcovParent,itGRID, itDOMAIN | itCOORDSYSTEM | itGEOREF);
    gcov->size(Size(size().xsize(), size().ysize()));
    gcov->_grid.reset(gcov->_grid->clone(index1, index2));

    return gcov;

}

IGridCoverage GridCoverage::get(const QString &item1, const QString &item2)
{
    IDomain indexDomain = datadef().domain(DataDefinition::daINDEX);
    if (!indexDomain.isValid())
        return IGridCoverage();
    if ( indexDomain->valueType() == itNUMERICITEM)  {
        bool ok;
        double item1Index = item1.toDouble(&ok);
        if (!ok){
            ERROR2(ERR_INVALID_PROPERTY_FOR_2, TR("item boundary"), TR("Sub setting"));
        }

        INumericItemDomain numdom = indexDomain.get<NumericItemDomain>();
        SPNumericItemRange numrange = numdom->range<NumericItemRange>();
        double index1 = numrange->index(item1Index);
        if ( index1 == rUNDEF){
            ERROR2(ERR_INVALID_PROPERTY_FOR_2, TR("item boundary"), TR("Sub setting"));
            return IGridCoverage();
        }
        int ind = 0;
        QString basename = name();
        if( (ind=basename.lastIndexOf(".")) != -1){
            basename = basename.left(ind);
        }
        QString cname, expr;
        double rest1 = index1 - (int)index1;
        if ( std::abs(rest1) > EPS8 && numrange->isContinous()) {
            int lowerIndex = std::floor(index1);
            double rest2 = 1.0 - rest1;
            expr = numrange->interpolation();
            cname = QString("%1_%2_%3").arg(basename).arg(lowerIndex).arg(lowerIndex+1);
            expr = cname + "=" + expr.arg(QString("%1*%2[%3]").arg(rest2).arg(name()).arg(lowerIndex)).arg(QString("%1*%2[%3]").arg(rest1).arg(name()).arg(lowerIndex+1));
        } else {
            cname = QString("%1_%2").arg(basename).arg(index1);
            expr = QString("%1=%2[%3]").arg(cname).arg(name()).arg(index1);

        }
        IGridCoverage mp = Operation::calculate<IGridCoverage>(cname,expr);
        if ( mp.isValid())
            return mp;
    }
    return IGridCoverage();
}

Grid *GridCoverage::grid()
{
    Locker lock(_mutex);
    if ( _georef->isValid() && !connector().isNull()) {
        if ( _grid.isNull()) {
            _grid.reset(connector()->loadGridData(this));
            if (_grid.isNull())
                return 0;
        }
        Grid *grd = _grid.data();
        return grd;
    }
    return 0;
}

void GridCoverage::copyTo(IlwisObject *obj)
{
    Locker lock(_mutex);
    Coverage::copyTo(obj);
    GridCoverage *gc = static_cast<GridCoverage *>(obj);
    gc->_georef = _georef;
    if ( _grid) {
        gc->_grid.reset(_grid->clone());
    }

}

Resource GridCoverage::resource(int mode) const
{
    Resource res = Coverage::resource(mode);
    if ( mode & IlwisObject::cmEXTENDED) {
        res["georeference()"] = georeference()->id();
        res.setExtendedType( res.extendedType() | itGEOREF);
    }
    return res;
}

Size GridCoverage::size() const
{
    if (_size.isValid() && !_size.isNull())
        return _size;
    if (!_grid.isNull())
        const_cast<GridCoverage *>(this)->_size = _grid->size();
    else if ( _georef.isValid())
        const_cast<GridCoverage *>(this)->_size = _georef->size();

    return _size;

}

void GridCoverage::size(const Size &sz)
{
    // size must always be positive or undefined
    if (sz.xsize() > 0 && sz.ysize() > 0) {
        _size = sz;
        if (!_grid.isNull())
            _grid->setSize(sz);
        if (_georef.isValid())
            _georef->size(sz);
    }

}

<|endoftext|>


<commit_before>#include <QString>
#include <QSharedPointer>
#include "kernel.h"
#include "range.h"
#include "domainitem.h"
#include "itemrange.h"
#include "identifieritem.h"
#include "identifierrange.h"

using namespace Ilwis;

IndexedIdentifier::IndexedIdentifier() : _index(0),_prefix("")
{
}

IndexedIdentifier::IndexedIdentifier(const QString &label, quint32 ind, qint32 cnt)
{
    _prefix = label;
    _index = ind;
    if ( cnt != iUNDEF)
        _count = cnt;
}

QString IndexedIdentifier::name(quint32 ind) const
{
    if ( _prefix != "")
        return QString("%1_%2").arg(_prefix).arg(_index + ind);
    return QString::number(_index + ind);
}

quint32 IndexedIdentifier::index() const
{
    return _index;
}

void IndexedIdentifier::setIndex(quint32 ind)
{
    _index = ind;
}

QString IndexedIdentifier::prefix() const
{
    return _prefix;
}

void IndexedIdentifier::setPrefix(const QString &pf)
{
    _prefix = pf;
}

bool IndexedIdentifier::operator==(const IndexedIdentifier &item) const
{
    return _prefix == item._prefix && _index == item._index;
}

DomainItem *IndexedIdentifier::clone() const
{
    return new IndexedIdentifier(_prefix, _index);
}

bool IndexedIdentifier::isValid() const{
    return true;
}

QString IndexedIdentifier::itemType() const
{
    return "IndexedIdentifier";
}

ItemRange *IndexedIdentifier::createRange()
{
    return new IndexedIdentifierRange();
}

//---------------------------------------------------------------
NamedIdentifier::NamedIdentifier() : _name(sUNDEF)
{
}

NamedIdentifier::NamedIdentifier(const QString &nm) : _name(nm)
{
}

QString NamedIdentifier::name(quint32 ) const
{
    return _name;
}

void NamedIdentifier::setName(const QString &n)
{
    _name = n;
}

bool NamedIdentifier::operator ==(const NamedIdentifier &item) const
{
    return _name == item.name();
}

QString NamedIdentifier::itemType() const
{
    return "NamedIdentifier";
}

NamedIdentifierRange *NamedIdentifier::createRange()
{
    return new NamedIdentifierRange();
}

DomainItem *NamedIdentifier::clone() const
{
    return new NamedIdentifier(_name);
}

bool NamedIdentifier::isValid() const {
    return _name != sUNDEF && _name != "";
}

<commit_msg>correct initialization of identifier item<commit_after>#include <QString>
#include <QSharedPointer>
#include "kernel.h"
#include "range.h"
#include "domainitem.h"
#include "itemrange.h"
#include "identifieritem.h"
#include "identifierrange.h"

using namespace Ilwis;

IndexedIdentifier::IndexedIdentifier() : _index(0),_prefix(""),_count(iUNDEF)
{
}

IndexedIdentifier::IndexedIdentifier(const QString &label, quint32 ind, qint32 cnt)
{
    _prefix = label;
    _index = ind;
    if ( cnt != iUNDEF)
        _count = cnt;
}

QString IndexedIdentifier::name(quint32 ind) const
{
    if ( _prefix != "")
        return QString("%1_%2").arg(_prefix).arg(_index + ind);
    return QString::number(_index + ind);
}

quint32 IndexedIdentifier::index() const
{
    return _index;
}

void IndexedIdentifier::setIndex(quint32 ind)
{
    _index = ind;
}

QString IndexedIdentifier::prefix() const
{
    return _prefix;
}

void IndexedIdentifier::setPrefix(const QString &pf)
{
    _prefix = pf;
}

bool IndexedIdentifier::operator==(const IndexedIdentifier &item) const
{
    return _prefix == item._prefix && _index == item._index;
}

DomainItem *IndexedIdentifier::clone() const
{
    return new IndexedIdentifier(_prefix, _index, _count);
}

bool IndexedIdentifier::isValid() const{
    return true;
}

QString IndexedIdentifier::itemType() const
{
    return "IndexedIdentifier";
}

ItemRange *IndexedIdentifier::createRange()
{
    return new IndexedIdentifierRange();
}

//---------------------------------------------------------------
NamedIdentifier::NamedIdentifier() : _name(sUNDEF)
{
}

NamedIdentifier::NamedIdentifier(const QString &nm) : _name(nm)
{
}

QString NamedIdentifier::name(quint32 ) const
{
    return _name;
}

void NamedIdentifier::setName(const QString &n)
{
    _name = n;
}

bool NamedIdentifier::operator ==(const NamedIdentifier &item) const
{
    return _name == item.name();
}

QString NamedIdentifier::itemType() const
{
    return "NamedIdentifier";
}

NamedIdentifierRange *NamedIdentifier::createRange()
{
    return new NamedIdentifierRange();
}

DomainItem *NamedIdentifier::clone() const
{
    return new NamedIdentifier(_name);
}

bool NamedIdentifier::isValid() const {
    return _name != sUNDEF && _name != "";
}

<|endoftext|>


<commit_before>/*MIT License

Copyright (c) 2018 MTA SZTAKI

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 "apePluginManagerImpl.h"
#include "rapidjson/document.h"
#include "rapidjson/filereadstream.h"

ape::PluginManagerImpl::PluginManagerImpl()
{
	msSingleton = this;
	mpCoreConfig = ape::ICoreConfig::getSingletonPtr();
	mThreadVector = std::vector<std::thread>();
	mPluginVector = std::vector<ape::IPlugin*>();
	mPluginCount = 0;
}

ape::PluginManagerImpl::~PluginManagerImpl()
{

}

void ape::PluginManagerImpl::CreatePlugin(std::string pluginname)
{
	mPluginVector.push_back(ape::PluginFactory::CreatePlugin(pluginname));
}

void ape::PluginManagerImpl::CreatePlugins()
{
	mpInternalPluginManager = &ape::InternalPluginManager::GetInstance();
	auto pluginNames = mpCoreConfig->getPluginNames();
	mPluginCount = pluginNames.size();
	for (std::vector<std::string>::iterator it = pluginNames.begin(); it != pluginNames.end(); ++it)
	{
		if (mpInternalPluginManager->Load((*it)))
		{
			CreatePlugin(*it);
			APE_LOG_DEBUG("Plugin loaded: " << *it);
		}
		else
		{
			mPluginCount--;
			APE_LOG_ERROR("Can not load plugin: " << *it);
		}
	}
}

void ape::PluginManagerImpl::InitAndRunPlugin(ape::IPlugin* plugin)
{
	plugin->Init();
	plugin->Run();
	//TODO_CORE name
	//ape::PluginFactory::UnregisterPlugin(pluginname, plugin);
}

void ape::PluginManagerImpl::InitAndRunPlugins()
{
	for (std::vector<ape::IPlugin*>::iterator it = mPluginVector.begin(); it != mPluginVector.end(); ++it)
	{
		mThreadVector.push_back(std::thread(&PluginManagerImpl::InitAndRunPlugin, this, (*it)));
	}
}

void ape::PluginManagerImpl::registerUserThreadFunction(std::function<void()> userThreadFunction)
{
	mThreadVector.push_back(std::thread(userThreadFunction));
}

void ape::PluginManagerImpl::joinThreads()
{
	std::for_each(mThreadVector.begin(), mThreadVector.end(), std::mem_fn(&std::thread::join));
}

void ape::PluginManagerImpl::detachThreads()
{
	std::for_each(mThreadVector.begin(), mThreadVector.end(), std::mem_fn(&std::thread::detach));
}

unsigned int ape::PluginManagerImpl::getPluginCount()
{
	return mPluginCount;
}

<commit_msg>Delete ApePluginManagerImpl.cpp<commit_after><|endoftext|>


<commit_before>/*
 * NetworkClient.cpp
 *
 *  Created on: 07.04.2016
 *      Author: Marc Hartung
 */

#include "../../include/network_impl/NetworkMember.hpp"

#include <iostream>
#include <algorithm>

namespace NetOff
{

    NetworkMember::NetworkMember()
            : _socket(nullptr),
              _maxBuffer(1024),
              _sleepTime(1000),
              _numMaxSleeps(100)
    {

    }

    NetworkMember::~NetworkMember()
    {
        killSocket(_socket);
    }

    bool NetworkMember::send(const char* buffer, const int & num)
    {
        int numBits = -1;
        int i = 0;
        while (i < num)
        {
            int partNum = std::min(num, i + _maxBuffer) - i;
            numBits = SDLNet_TCP_Send(_socket, static_cast<const void *>(&buffer[i]), partNum);

            if (numBits > 0)
                i += numBits;
            else if (i == numBits && i < num)
            {
                std::cout << "Connection send fail.\n";
                return false;
            }
        }

        //std::cout << getChar() << " sending " << num << " bytes\n";
        return true;
    }

    bool NetworkMember::recv(char* buffer, const int & num)
    {
        int numBytes = -1;
        int i = 0;
        while (i < num)
        {
            unsigned partNum = std::min(num, i + _maxBuffer) - i;
            numBytes = SDLNet_TCP_Recv(_socket, &buffer[i], partNum);
            if (numBytes > 0)
                i += numBytes;
            else if (i == 0 && i < num)
            {
                std::cout << "Connection recv fail.\n";
                return false;
            }

        }
        //std::cout << getChar() << " receiving " << num << " bytes\n";
        return true;
    }

    bool NetworkMember::variableSend(const char* buffer, const int & num)
    {
        int numCopy = num;
        if (!send(reinterpret_cast<char *>(&numCopy), sizeof(numCopy))) // Send size
            return false;
        return send(buffer, num);                                       // Send buffer
    }

    std::shared_ptr<char> NetworkMember::variableRecv(size_t * numBytes)
    {
        int num = 0;
        recv(reinterpret_cast<char*>(&num), sizeof(num));
        std::shared_ptr<char> res(new char[num]);
        recv(res.get(), num);
        if (numBytes != nullptr)
        {
            *numBytes = num;
        }
        return res;
    }

    void NetworkMember::killSocket(TCPsocket& socket)
    {
        {
            if (socket != nullptr)
            {
                SDLNet_TCP_Close(socket);
                socket = nullptr;
            }
        }
    }

} /* namespace NetOff */

<commit_msg>When using make shared to create arrays we need to make sure, that delete[] is called<commit_after>/*
 * NetworkClient.cpp
 *
 *  Created on: 07.04.2016
 *      Author: Marc Hartung
 */

#include "network_impl/NetworkMember.hpp"

#include <iostream>
#include <algorithm>

namespace NetOff
{

    NetworkMember::NetworkMember()
            : _socket(nullptr),
              _maxBuffer(1024),
              _sleepTime(1000),
              _numMaxSleeps(100)
    {

    }

    NetworkMember::~NetworkMember()
    {
        killSocket(_socket);
    }

    bool NetworkMember::send(const char* buffer, const int & num)
    {
        int numBits = -1;
        int i = 0;
        while (i < num)
        {
            int partNum = std::min(num, i + _maxBuffer) - i;
            numBits = SDLNet_TCP_Send(_socket, static_cast<const void *>(&buffer[i]), partNum);

            if (numBits > 0)
                i += numBits;
            else if (i == numBits && i < num)
            {
                std::cout << "Connection send fail.\n";
                return false;
            }
        }

        //std::cout << getChar() << " sending " << num << " bytes\n";
        return true;
    }

    bool NetworkMember::recv(char* buffer, const int & num)
    {
        int numBytes = -1;
        int i = 0;
        while (i < num)
        {
            unsigned partNum = std::min(num, i + _maxBuffer) - i;
            numBytes = SDLNet_TCP_Recv(_socket, &buffer[i], partNum);
            if (numBytes > 0)
                i += numBytes;
            else if (i == 0 && i < num)
            {
                std::cout << "Connection recv fail.\n";
                return false;
            }

        }
        //std::cout << getChar() << " receiving " << num << " bytes\n";
        return true;
    }

    bool NetworkMember::variableSend(const char* buffer, const int & num)
    {
        int numCopy = num;
        if (!send(reinterpret_cast<char *>(&numCopy), sizeof(numCopy))) // Send size
            return false;
        return send(buffer, num);                                       // Send buffer
    }

    std::shared_ptr<char> NetworkMember::variableRecv(size_t * numBytes)
    {
        int num = 0;
        recv(reinterpret_cast<char*>(&num), sizeof(num));
        std::shared_ptr<char> res(new char[num], std::default_delete<char[]>());
        recv(res.get(), num);
        if (numBytes != nullptr)
        {
            *numBytes = num;
        }
        return res;
    }

    void NetworkMember::killSocket(TCPsocket& socket)
    {
        {
            if (socket != nullptr)
            {
                SDLNet_TCP_Close(socket);
                socket = nullptr;
            }
        }
    }

} /* namespace NetOff */

<|endoftext|>


<commit_before>#include <utility>
#include "api/halley_api.h"
#include <halley/plugin/plugin.h>
#include "halley/audio/audio_facade.h"
#include "halley/support/logger.h"
#include "entry/entry_point.h"

using namespace Halley;

void HalleyAPI::assign()
{
	Expects(coreInternal != nullptr);
	Expects(systemInternal != nullptr);

	core = coreInternal;
	system = systemInternal.get();

	if (videoInternal) {
		video = videoInternal.get();
	}
	if (inputInternal) {
		input = inputInternal.get();
	}
	if (audioInternal) {
		audio = audioInternal.get();
	}
	if (platformInternal) {
		platform = platformInternal.get();
	}
	if (networkInternal) {
		network = networkInternal.get();
	}
	if (movieInternal) {
		movie = movieInternal.get();
	}
}

void HalleyAPI::init()
{
	if (systemInternal) {
		systemInternal->init();
	}
	if (videoInternal) {
		videoInternal->init();
	}
	if (inputInternal) {
		inputInternal->init();
	}
	if (audioOutputInternal) {
		audioOutputInternal->init();
	}
	if (audioInternal) {
		audioInternal->init();
	}
	if (platformInternal) {
		platformInternal->init();
	}
	if (networkInternal) {
		networkInternal->init();
	}
	if (movieInternal) {
		movieInternal->init();
	}
}

void HalleyAPI::deInit()
{
	if (movieInternal) {
		movieInternal->deInit();
	}
	if (networkInternal) {
		networkInternal->deInit();
	}
	if (platformInternal) {
		platformInternal->deInit();
	}
	if (audioInternal) {
		audioInternal->deInit();
	}
	if (audioOutputInternal) {
		audioOutputInternal->deInit();
	}
	if (inputInternal) {
		inputInternal->deInit();
	}
	if (videoInternal) {
		videoInternal->deInit();
	}
	if (systemInternal) {
		systemInternal->deInit();
	}
}

std::unique_ptr<HalleyAPI> HalleyAPI::create(CoreAPIInternal* core, int flags)
{
	auto api = std::make_unique<HalleyAPI>();
	api->coreInternal = core;

	HalleyAPIFlags::Flags flagList[] = { HalleyAPIFlags::System, HalleyAPIFlags::Video, HalleyAPIFlags::Input, HalleyAPIFlags::Audio, HalleyAPIFlags::Network, HalleyAPIFlags::Platform, HalleyAPIFlags::Movie };
	PluginType pluginTypes[] = { PluginType::SystemAPI, PluginType::GraphicsAPI, PluginType::InputAPI, PluginType::AudioOutputAPI, PluginType::NetworkAPI, PluginType::PlatformAPI, PluginType::MovieAPI };
	String names[] = { "System", "Graphics", "Input", "AudioOutput", "Network", "Platform", "Movie" };

	constexpr size_t n = std::end(flagList) - std::begin(flagList);
	for (size_t i = 0; i < n; ++i) {
		if (flags & flagList[i] || flagList[i] == HalleyAPIFlags::System) {
			auto plugins = core->getPlugins(pluginTypes[i]);
			if (!plugins.empty()) {
				Logger::logInfo(names[i] + " plugin: " + plugins[0]->getName());
				api->setAPI(pluginTypes[i], plugins[0]->createAPI(api->systemInternal.get()));
			} else {
				throw Exception("No suitable " + names[i] + " plugins found.", HalleyExceptions::Core);
			}
		}
	}

	api->assign();
	return api;
}

void HalleyAPI::setAPI(PluginType pluginType, HalleyAPIInternal* api)
{
	switch (pluginType) {
	case PluginType::SystemAPI:
		systemInternal.reset(dynamic_cast<SystemAPIInternal*>(api));
		return;
	case PluginType::InputAPI:
		inputInternal.reset(dynamic_cast<InputAPIInternal*>(api));
		return;
	case PluginType::GraphicsAPI:
		videoInternal.reset(dynamic_cast<VideoAPIInternal*>(api));
		return;
	case PluginType::AudioOutputAPI:
		audioOutputInternal.reset(dynamic_cast<AudioOutputAPIInternal*>(api));
		audioInternal = std::make_unique<AudioFacade>(*audioOutputInternal, *systemInternal);
		return;
	case PluginType::PlatformAPI:
		platformInternal.reset(dynamic_cast<PlatformAPIInternal*>(api));
		return;
	case PluginType::NetworkAPI:
		networkInternal.reset(dynamic_cast<NetworkAPIInternal*>(api));
		return;
	case PluginType::MovieAPI:
		movieInternal.reset(dynamic_cast<MovieAPIInternal*>(api));
		return;
	}
}

HalleyAPI& HalleyAPI::operator=(const HalleyAPI& other) = default;

std::unique_ptr<HalleyAPI> HalleyAPI::clone() const
{
	auto api = std::make_unique<HalleyAPI>();
	*api = *this;
	return api;
}

void HalleyAPI::replaceCoreAPI(CoreAPIInternal* coreAPI)
{
	coreInternal = coreAPI;
	core = coreAPI;
}

uint32_t Halley::getHalleyDLLAPIVersion()
{
	return 188;
}
<commit_msg>Bump version<commit_after>#include <utility>
#include "api/halley_api.h"
#include <halley/plugin/plugin.h>
#include "halley/audio/audio_facade.h"
#include "halley/support/logger.h"
#include "entry/entry_point.h"

using namespace Halley;

void HalleyAPI::assign()
{
	Expects(coreInternal != nullptr);
	Expects(systemInternal != nullptr);

	core = coreInternal;
	system = systemInternal.get();

	if (videoInternal) {
		video = videoInternal.get();
	}
	if (inputInternal) {
		input = inputInternal.get();
	}
	if (audioInternal) {
		audio = audioInternal.get();
	}
	if (platformInternal) {
		platform = platformInternal.get();
	}
	if (networkInternal) {
		network = networkInternal.get();
	}
	if (movieInternal) {
		movie = movieInternal.get();
	}
}

void HalleyAPI::init()
{
	if (systemInternal) {
		systemInternal->init();
	}
	if (videoInternal) {
		videoInternal->init();
	}
	if (inputInternal) {
		inputInternal->init();
	}
	if (audioOutputInternal) {
		audioOutputInternal->init();
	}
	if (audioInternal) {
		audioInternal->init();
	}
	if (platformInternal) {
		platformInternal->init();
	}
	if (networkInternal) {
		networkInternal->init();
	}
	if (movieInternal) {
		movieInternal->init();
	}
}

void HalleyAPI::deInit()
{
	if (movieInternal) {
		movieInternal->deInit();
	}
	if (networkInternal) {
		networkInternal->deInit();
	}
	if (platformInternal) {
		platformInternal->deInit();
	}
	if (audioInternal) {
		audioInternal->deInit();
	}
	if (audioOutputInternal) {
		audioOutputInternal->deInit();
	}
	if (inputInternal) {
		inputInternal->deInit();
	}
	if (videoInternal) {
		videoInternal->deInit();
	}
	if (systemInternal) {
		systemInternal->deInit();
	}
}

std::unique_ptr<HalleyAPI> HalleyAPI::create(CoreAPIInternal* core, int flags)
{
	auto api = std::make_unique<HalleyAPI>();
	api->coreInternal = core;

	HalleyAPIFlags::Flags flagList[] = { HalleyAPIFlags::System, HalleyAPIFlags::Video, HalleyAPIFlags::Input, HalleyAPIFlags::Audio, HalleyAPIFlags::Network, HalleyAPIFlags::Platform, HalleyAPIFlags::Movie };
	PluginType pluginTypes[] = { PluginType::SystemAPI, PluginType::GraphicsAPI, PluginType::InputAPI, PluginType::AudioOutputAPI, PluginType::NetworkAPI, PluginType::PlatformAPI, PluginType::MovieAPI };
	String names[] = { "System", "Graphics", "Input", "AudioOutput", "Network", "Platform", "Movie" };

	constexpr size_t n = std::end(flagList) - std::begin(flagList);
	for (size_t i = 0; i < n; ++i) {
		if (flags & flagList[i] || flagList[i] == HalleyAPIFlags::System) {
			auto plugins = core->getPlugins(pluginTypes[i]);
			if (!plugins.empty()) {
				Logger::logInfo(names[i] + " plugin: " + plugins[0]->getName());
				api->setAPI(pluginTypes[i], plugins[0]->createAPI(api->systemInternal.get()));
			} else {
				throw Exception("No suitable " + names[i] + " plugins found.", HalleyExceptions::Core);
			}
		}
	}

	api->assign();
	return api;
}

void HalleyAPI::setAPI(PluginType pluginType, HalleyAPIInternal* api)
{
	switch (pluginType) {
	case PluginType::SystemAPI:
		systemInternal.reset(dynamic_cast<SystemAPIInternal*>(api));
		return;
	case PluginType::InputAPI:
		inputInternal.reset(dynamic_cast<InputAPIInternal*>(api));
		return;
	case PluginType::GraphicsAPI:
		videoInternal.reset(dynamic_cast<VideoAPIInternal*>(api));
		return;
	case PluginType::AudioOutputAPI:
		audioOutputInternal.reset(dynamic_cast<AudioOutputAPIInternal*>(api));
		audioInternal = std::make_unique<AudioFacade>(*audioOutputInternal, *systemInternal);
		return;
	case PluginType::PlatformAPI:
		platformInternal.reset(dynamic_cast<PlatformAPIInternal*>(api));
		return;
	case PluginType::NetworkAPI:
		networkInternal.reset(dynamic_cast<NetworkAPIInternal*>(api));
		return;
	case PluginType::MovieAPI:
		movieInternal.reset(dynamic_cast<MovieAPIInternal*>(api));
		return;
	}
}

HalleyAPI& HalleyAPI::operator=(const HalleyAPI& other) = default;

std::unique_ptr<HalleyAPI> HalleyAPI::clone() const
{
	auto api = std::make_unique<HalleyAPI>();
	*api = *this;
	return api;
}

void HalleyAPI::replaceCoreAPI(CoreAPIInternal* coreAPI)
{
	coreInternal = coreAPI;
	core = coreAPI;
}

uint32_t Halley::getHalleyDLLAPIVersion()
{
	return 189;
}
<|endoftext|>