<commit_before>#include "dreal/dreal_main.h"

#include <csignal>
#include <cstdlib>
#include <iostream>

#include "dreal/dr/run.h"
#include "dreal/smt2/run.h"
#include "dreal/solver/context.h"
#include "dreal/util/exception.h"
#include "dreal/util/filesystem.h"
#include "dreal/util/logging.h"

namespace dreal {

using std::cerr;
using std::endl;
using std::string;
using std::vector;

MainProgram::MainProgram(int argc, const char* argv[]) {
  AddOptions();
  opt_.parse(argc, argv);  // Parse Options
  is_options_all_valid_ = ValidateOptions();
}

void MainProgram::PrintUsage() {
  string usage;
  opt_.getUsage(usage);
  cerr << usage;
}

void MainProgram::AddOptions() {
#ifndef NDEBUG
  const string build_type{"Debug"};
#else
  const string build_type{"Release"};
#endif
  opt_.overview =
      fmt::format("dReal v{} ({} Build) : delta-complete SMT solver",
                  Context::version(), build_type);
  opt_.syntax = "dreal [OPTIONS] <input file> (.smt2 or .dr)";

  // NOTE: Make sure to match the default values specified here with the ones
  // specified in dreal/solver/config.h.
  opt_.add("" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Display usage instructions.", "-h", "-help", "--help", "--usage");

  auto* const positive_double_option_validator =
      new ez::ezOptionValidator("d" /* double */, "gt", "0");

  auto* const positive_int_option_validator =
      new ez::ezOptionValidator("s4" /* 4byte integer */, "gt", "0");

  opt_.add("0.001" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Precision (default = 0.001)\n", "--precision",
           positive_double_option_validator);

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Produce models if delta-sat\n", "--produce-models", "--model");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Debug scanning/lexing\n", "--debug-scanning");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */, "Debug parsing\n",
           "--debug-parsing");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Read from standard input. Uses smt2 by default.\n", "--in");

  auto* const format_option_validator =
      new ez::ezOptionValidator("t", "in", "auto,dr,smt2", false);
  opt_.add("auto" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "File format. Any one of these (default = auto):\n"
           "smt2, dr, auto (use file extension)\n",
           "--format", format_option_validator);

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use polytope contractor.\n", "--polytope");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use polytope contractor in forall contractor.\n",
           "--forall-polytope");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use worklist fixpoint algorithm in ICP.\n", "--worklist-fixpoint");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use local optimization algorithm for exist-forall problems.\n",
           "--local-optimization");

  opt_.add("1e-6" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Relative tolerance on function value (default = 1e-6)\n",
           "--nlopt-ftol-rel", positive_double_option_validator);

  opt_.add("1e-6" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Absolute tolerance on function value (default = 1e-6)\n",
           "--nlopt-ftol-abs", positive_double_option_validator);

  opt_.add("100" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Number of maximum function evaluations (default = 100)\n",
           "--nlopt-maxeval", positive_int_option_validator);

  opt_.add(
      "0.1" /* Default */, false /* Required? */,
      1 /* Number of args expected. */,
      0 /* Delimiter if expecting multiple args. */,
      "[NLopt] Maximum optimization time (in second) (default = 0.01 sec)\n",
      "--nlopt-maxtime", positive_double_option_validator);

  auto* const verbose_option_validator = new ez::ezOptionValidator(
      "t", "in", "trace,debug,info,warning,error,critical,off", true);
  opt_.add(
      "error",  // Default.
      0,        // Required?
      1,        // Number of args expected.
      0,        // Delimiter if expecting multiple args.
      "Verbosity level. Either one of these (default = error):\n"
      "trace, debug, info, warning, error, critical, off",  // Help description.
      "--verbose",                                          // Flag token.
      verbose_option_validator);

  opt_.add("2" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Set default initial phase for SAT solver.\n"
           "  0 = false\n"
           "  1 = true\n"
           "  2 = Jeroslow-Wang (default)\n"
           "  3 = random initial phase\n",
           "--sat-default-phase");

  opt_.add("0" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Set a seed for the random number generator.", "--random-seed");
}

bool MainProgram::ValidateOptions() {
  // Checks bad options and bad arguments.
  vector<string> bad_options;
  vector<string> bad_args;
  if (!opt_.gotRequired(bad_options)) {
    for (const auto& bad_option : bad_options) {
      cerr << "ERROR: Missing required option " << bad_option << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  if (!opt_.gotExpected(bad_options)) {
    for (const auto& bad_option : bad_options) {
      cerr << "ERROR: Got unexpected number of arguments for option "
           << bad_option << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  if (!opt_.gotValid(bad_options, bad_args)) {
    for (size_t i = 0; i < bad_options.size(); ++i) {
      cerr << "ERROR: Got invalid argument \"" << bad_args[i]
           << "\" for option " << bad_options[i] << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  // After filtering out bad options/arguments, save the valid ones in `args_`.
  args_.insert(args_.end(), opt_.firstArgs.begin() + 1, opt_.firstArgs.end());
  args_.insert(args_.end(), opt_.unknownArgs.begin(), opt_.unknownArgs.end());
  args_.insert(args_.end(), opt_.lastArgs.begin(), opt_.lastArgs.end());
  if (opt_.isSet("-h") || (args_.empty() && !opt_.isSet("--in")) ||
      args_.size() > 1) {
    PrintUsage();
    return false;
  }
  return true;
}

void MainProgram::ExtractOptions() {
  // Temporary variables used to set options.
  string verbosity;
  opt_.get("--verbose")->getString(verbosity);
  if (verbosity == "trace") {
    log()->set_level(spdlog::level::trace);
  } else if (verbosity == "debug") {
    log()->set_level(spdlog::level::debug);
  } else if (verbosity == "info") {
    log()->set_level(spdlog::level::info);
  } else if (verbosity == "warning") {
    log()->set_level(spdlog::level::warn);
  } else if (verbosity == "error") {
    log()->set_level(spdlog::level::err);
  } else if (verbosity == "critical") {
    log()->set_level(spdlog::level::critical);
  } else {
    log()->set_level(spdlog::level::off);
  }

  // --precision
  if (opt_.isSet("--precision")) {
    double precision{0.0};
    opt_.get("--precision")->getDouble(precision);
    config_.mutable_precision().set_from_command_line(precision);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --precision = {}",
                    config_.precision());
  }

  // --produce-model
  if (opt_.isSet("--produce-models")) {
    config_.mutable_produce_models().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --produce-models = {}",
                    config_.produce_models());
  }

  // --polytope
  if (opt_.isSet("--polytope")) {
    config_.mutable_use_polytope().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --polytope = {}",
                    config_.use_polytope());
  }

  // --forall-polytope
  if (opt_.isSet("--forall-polytope")) {
    config_.mutable_use_polytope_in_forall().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --forall-polytope = {}",
                    config_.use_polytope_in_forall());
  }

  // --worklist-fixpoint
  if (opt_.isSet("--worklist-fixpoint")) {
    config_.mutable_use_worklist_fixpoint().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --worklist-fixpoint = {}",
                    config_.use_worklist_fixpoint());
  }

  // --local-optimization
  if (opt_.isSet("--local-optimization")) {
    config_.mutable_use_local_optimization().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --local-optimization = {}",
                    config_.use_local_optimization());
  }

  // --nlopt-ftol-rel
  double nlopt_ftol_rel{0.0};
  if (opt_.isSet("--nlopt-ftol-rel")) {
    opt_.get("--nlopt-ftol-rel")->getDouble(nlopt_ftol_rel);
    config_.mutable_nlopt_ftol_rel().set_from_command_line(nlopt_ftol_rel);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-ftol-rel = {}",
                    config_.nlopt_ftol_rel());
  }

  // --nlopt-ftol-abs
  if (opt_.isSet("--nlopt-ftol-abs")) {
    double nlopt_ftol_abs{0.0};
    opt_.get("--nlopt-ftol-abs")->getDouble(nlopt_ftol_abs);
    config_.mutable_nlopt_ftol_abs().set_from_command_line(nlopt_ftol_abs);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-ftol-abs = {}",
                    config_.nlopt_ftol_abs());
  }

  // --nlopt-maxeval
  if (opt_.isSet("--nlopt-maxeval")) {
    int nlopt_maxeval{0};
    opt_.get("--nlopt-maxeval")->getInt(nlopt_maxeval);
    config_.mutable_nlopt_maxeval().set_from_command_line(nlopt_maxeval);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-maxeval = {}",
                    config_.nlopt_maxeval());
  }

  // --nlopt-maxtime
  if (opt_.isSet("--nlopt-maxtime")) {
    double nlopt_maxtime{0.0};
    opt_.get("--nlopt-maxtime")->getDouble(nlopt_maxtime);
    config_.mutable_nlopt_maxtime().set_from_command_line(nlopt_maxtime);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-maxtime = {}",
                    config_.nlopt_maxtime());
  }

  // --sat-default-phase
  if (opt_.isSet("--sat-default-phase")) {
    int sat_default_phase{2};
    opt_.get("--sat-default-phase")->getInt(sat_default_phase);
    config_.mutable_sat_default_phase().set_from_command_line(
        static_cast<Config::SatDefaultPhase>(sat_default_phase));
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --sat-default-phase = {}",
                    config_.sat_default_phase());
  }

  // --random-seed
  if (opt_.isSet("--random-seed")) {
    // NOLINTNEXTLINE(runtime/int)
    static_assert(sizeof(unsigned long) == sizeof(std::uint64_t),
                  "sizeof(unsigned long) != sizeof(std::uint64_t).");
    std::uint64_t random_seed{0};
    opt_.get("--random-seed")->getULong(random_seed);
    config_.mutable_random_seed().set_from_command_line(random_seed);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --random-seed = {}",
                    config_.random_seed());
  }
}

int MainProgram::Run() {
  if (!is_options_all_valid_) {
    return 1;
  }
  ExtractOptions();
  string filename;
  if (!args_.empty()) {
    filename = *args_[0];
    if (filename.empty()) {
      PrintUsage();
      return 1;
    }
  }
  if (!opt_.isSet("--in") && !file_exists(filename)) {
    cerr << "File not found: " << filename << "\n" << endl;
    PrintUsage();
    return 1;
  }
  const string extension{get_extension(filename)};
  string format_opt;
  opt_.get("--format")->getString(format_opt);
  if (format_opt == "smt2" ||
      (format_opt == "auto" && (extension == "smt2" || opt_.isSet("--in")))) {
    RunSmt2(filename, config_, opt_.isSet("--debug-scanning"),
            opt_.isSet("--debug-parsing"));
  } else if (format_opt == "dr" ||
             (format_opt == "auto" && extension == "dr")) {
    RunDr(filename, config_, opt_.isSet("--debug-scanning"),
          opt_.isSet("--debug-parsing"));
  } else {
    cerr << "Unknown extension: " << filename << "\n" << endl;
    PrintUsage();
    return 1;
  }
  return 0;
}
}  // namespace dreal

namespace {
void HandleSigInt(const int) {
  // Properly exit so that we can see stat information produced by destructors
  // even if a user press C-c.
  std::exit(1);
}
}  // namespace

int main(int argc, const char* argv[]) {
  std::signal(SIGINT, HandleSigInt);
  dreal::MainProgram main_program{argc, argv};
  return main_program.Run();
}
<commit_msg>fix(dreal_main.cc): Use unsigned long<commit_after>#include "dreal/dreal_main.h"

#include <csignal>
#include <cstdlib>
#include <iostream>

#include "dreal/dr/run.h"
#include "dreal/smt2/run.h"
#include "dreal/solver/context.h"
#include "dreal/util/exception.h"
#include "dreal/util/filesystem.h"
#include "dreal/util/logging.h"

namespace dreal {

using std::cerr;
using std::endl;
using std::string;
using std::vector;

MainProgram::MainProgram(int argc, const char* argv[]) {
  AddOptions();
  opt_.parse(argc, argv);  // Parse Options
  is_options_all_valid_ = ValidateOptions();
}

void MainProgram::PrintUsage() {
  string usage;
  opt_.getUsage(usage);
  cerr << usage;
}

void MainProgram::AddOptions() {
#ifndef NDEBUG
  const string build_type{"Debug"};
#else
  const string build_type{"Release"};
#endif
  opt_.overview =
      fmt::format("dReal v{} ({} Build) : delta-complete SMT solver",
                  Context::version(), build_type);
  opt_.syntax = "dreal [OPTIONS] <input file> (.smt2 or .dr)";

  // NOTE: Make sure to match the default values specified here with the ones
  // specified in dreal/solver/config.h.
  opt_.add("" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Display usage instructions.", "-h", "-help", "--help", "--usage");

  auto* const positive_double_option_validator =
      new ez::ezOptionValidator("d" /* double */, "gt", "0");

  auto* const positive_int_option_validator =
      new ez::ezOptionValidator("s4" /* 4byte integer */, "gt", "0");

  opt_.add("0.001" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Precision (default = 0.001)\n", "--precision",
           positive_double_option_validator);

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Produce models if delta-sat\n", "--produce-models", "--model");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Debug scanning/lexing\n", "--debug-scanning");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */, "Debug parsing\n",
           "--debug-parsing");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Read from standard input. Uses smt2 by default.\n", "--in");

  auto* const format_option_validator =
      new ez::ezOptionValidator("t", "in", "auto,dr,smt2", false);
  opt_.add("auto" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "File format. Any one of these (default = auto):\n"
           "smt2, dr, auto (use file extension)\n",
           "--format", format_option_validator);

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use polytope contractor.\n", "--polytope");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use polytope contractor in forall contractor.\n",
           "--forall-polytope");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use worklist fixpoint algorithm in ICP.\n", "--worklist-fixpoint");

  opt_.add("false" /* Default */, false /* Required? */,
           0 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Use local optimization algorithm for exist-forall problems.\n",
           "--local-optimization");

  opt_.add("1e-6" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Relative tolerance on function value (default = 1e-6)\n",
           "--nlopt-ftol-rel", positive_double_option_validator);

  opt_.add("1e-6" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Absolute tolerance on function value (default = 1e-6)\n",
           "--nlopt-ftol-abs", positive_double_option_validator);

  opt_.add("100" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "[NLopt] Number of maximum function evaluations (default = 100)\n",
           "--nlopt-maxeval", positive_int_option_validator);

  opt_.add(
      "0.1" /* Default */, false /* Required? */,
      1 /* Number of args expected. */,
      0 /* Delimiter if expecting multiple args. */,
      "[NLopt] Maximum optimization time (in second) (default = 0.01 sec)\n",
      "--nlopt-maxtime", positive_double_option_validator);

  auto* const verbose_option_validator = new ez::ezOptionValidator(
      "t", "in", "trace,debug,info,warning,error,critical,off", true);
  opt_.add(
      "error",  // Default.
      0,        // Required?
      1,        // Number of args expected.
      0,        // Delimiter if expecting multiple args.
      "Verbosity level. Either one of these (default = error):\n"
      "trace, debug, info, warning, error, critical, off",  // Help description.
      "--verbose",                                          // Flag token.
      verbose_option_validator);

  opt_.add("2" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Set default initial phase for SAT solver.\n"
           "  0 = false\n"
           "  1 = true\n"
           "  2 = Jeroslow-Wang (default)\n"
           "  3 = random initial phase\n",
           "--sat-default-phase");

  opt_.add("0" /* Default */, false /* Required? */,
           1 /* Number of args expected. */,
           0 /* Delimiter if expecting multiple args. */,
           "Set a seed for the random number generator.", "--random-seed");
}

bool MainProgram::ValidateOptions() {
  // Checks bad options and bad arguments.
  vector<string> bad_options;
  vector<string> bad_args;
  if (!opt_.gotRequired(bad_options)) {
    for (const auto& bad_option : bad_options) {
      cerr << "ERROR: Missing required option " << bad_option << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  if (!opt_.gotExpected(bad_options)) {
    for (const auto& bad_option : bad_options) {
      cerr << "ERROR: Got unexpected number of arguments for option "
           << bad_option << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  if (!opt_.gotValid(bad_options, bad_args)) {
    for (size_t i = 0; i < bad_options.size(); ++i) {
      cerr << "ERROR: Got invalid argument \"" << bad_args[i]
           << "\" for option " << bad_options[i] << ".\n\n";
    }
    PrintUsage();
    return false;
  }
  // After filtering out bad options/arguments, save the valid ones in `args_`.
  args_.insert(args_.end(), opt_.firstArgs.begin() + 1, opt_.firstArgs.end());
  args_.insert(args_.end(), opt_.unknownArgs.begin(), opt_.unknownArgs.end());
  args_.insert(args_.end(), opt_.lastArgs.begin(), opt_.lastArgs.end());
  if (opt_.isSet("-h") || (args_.empty() && !opt_.isSet("--in")) ||
      args_.size() > 1) {
    PrintUsage();
    return false;
  }
  return true;
}

void MainProgram::ExtractOptions() {
  // Temporary variables used to set options.
  string verbosity;
  opt_.get("--verbose")->getString(verbosity);
  if (verbosity == "trace") {
    log()->set_level(spdlog::level::trace);
  } else if (verbosity == "debug") {
    log()->set_level(spdlog::level::debug);
  } else if (verbosity == "info") {
    log()->set_level(spdlog::level::info);
  } else if (verbosity == "warning") {
    log()->set_level(spdlog::level::warn);
  } else if (verbosity == "error") {
    log()->set_level(spdlog::level::err);
  } else if (verbosity == "critical") {
    log()->set_level(spdlog::level::critical);
  } else {
    log()->set_level(spdlog::level::off);
  }

  // --precision
  if (opt_.isSet("--precision")) {
    double precision{0.0};
    opt_.get("--precision")->getDouble(precision);
    config_.mutable_precision().set_from_command_line(precision);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --precision = {}",
                    config_.precision());
  }

  // --produce-model
  if (opt_.isSet("--produce-models")) {
    config_.mutable_produce_models().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --produce-models = {}",
                    config_.produce_models());
  }

  // --polytope
  if (opt_.isSet("--polytope")) {
    config_.mutable_use_polytope().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --polytope = {}",
                    config_.use_polytope());
  }

  // --forall-polytope
  if (opt_.isSet("--forall-polytope")) {
    config_.mutable_use_polytope_in_forall().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --forall-polytope = {}",
                    config_.use_polytope_in_forall());
  }

  // --worklist-fixpoint
  if (opt_.isSet("--worklist-fixpoint")) {
    config_.mutable_use_worklist_fixpoint().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --worklist-fixpoint = {}",
                    config_.use_worklist_fixpoint());
  }

  // --local-optimization
  if (opt_.isSet("--local-optimization")) {
    config_.mutable_use_local_optimization().set_from_command_line(true);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --local-optimization = {}",
                    config_.use_local_optimization());
  }

  // --nlopt-ftol-rel
  double nlopt_ftol_rel{0.0};
  if (opt_.isSet("--nlopt-ftol-rel")) {
    opt_.get("--nlopt-ftol-rel")->getDouble(nlopt_ftol_rel);
    config_.mutable_nlopt_ftol_rel().set_from_command_line(nlopt_ftol_rel);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-ftol-rel = {}",
                    config_.nlopt_ftol_rel());
  }

  // --nlopt-ftol-abs
  if (opt_.isSet("--nlopt-ftol-abs")) {
    double nlopt_ftol_abs{0.0};
    opt_.get("--nlopt-ftol-abs")->getDouble(nlopt_ftol_abs);
    config_.mutable_nlopt_ftol_abs().set_from_command_line(nlopt_ftol_abs);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-ftol-abs = {}",
                    config_.nlopt_ftol_abs());
  }

  // --nlopt-maxeval
  if (opt_.isSet("--nlopt-maxeval")) {
    int nlopt_maxeval{0};
    opt_.get("--nlopt-maxeval")->getInt(nlopt_maxeval);
    config_.mutable_nlopt_maxeval().set_from_command_line(nlopt_maxeval);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-maxeval = {}",
                    config_.nlopt_maxeval());
  }

  // --nlopt-maxtime
  if (opt_.isSet("--nlopt-maxtime")) {
    double nlopt_maxtime{0.0};
    opt_.get("--nlopt-maxtime")->getDouble(nlopt_maxtime);
    config_.mutable_nlopt_maxtime().set_from_command_line(nlopt_maxtime);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --nlopt-maxtime = {}",
                    config_.nlopt_maxtime());
  }

  // --sat-default-phase
  if (opt_.isSet("--sat-default-phase")) {
    int sat_default_phase{2};
    opt_.get("--sat-default-phase")->getInt(sat_default_phase);
    config_.mutable_sat_default_phase().set_from_command_line(
        static_cast<Config::SatDefaultPhase>(sat_default_phase));
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --sat-default-phase = {}",
                    config_.sat_default_phase());
  }

  // --random-seed
  if (opt_.isSet("--random-seed")) {
    // NOLINTNEXTLINE(runtime/int)
    static_assert(sizeof(unsigned long) == sizeof(std::uint64_t),
                  "sizeof(unsigned long) != sizeof(std::uint64_t).");
    // NOLINTNEXTLINE(runtime/int)
    unsigned long random_seed{0};
    opt_.get("--random-seed")->getULong(random_seed);
    config_.mutable_random_seed().set_from_command_line(random_seed);
    DREAL_LOG_DEBUG("MainProgram::ExtractOptions() --random-seed = {}",
                    config_.random_seed());
  }
}

int MainProgram::Run() {
  if (!is_options_all_valid_) {
    return 1;
  }
  ExtractOptions();
  string filename;
  if (!args_.empty()) {
    filename = *args_[0];
    if (filename.empty()) {
      PrintUsage();
      return 1;
    }
  }
  if (!opt_.isSet("--in") && !file_exists(filename)) {
    cerr << "File not found: " << filename << "\n" << endl;
    PrintUsage();
    return 1;
  }
  const string extension{get_extension(filename)};
  string format_opt;
  opt_.get("--format")->getString(format_opt);
  if (format_opt == "smt2" ||
      (format_opt == "auto" && (extension == "smt2" || opt_.isSet("--in")))) {
    RunSmt2(filename, config_, opt_.isSet("--debug-scanning"),
            opt_.isSet("--debug-parsing"));
  } else if (format_opt == "dr" ||
             (format_opt == "auto" && extension == "dr")) {
    RunDr(filename, config_, opt_.isSet("--debug-scanning"),
          opt_.isSet("--debug-parsing"));
  } else {
    cerr << "Unknown extension: " << filename << "\n" << endl;
    PrintUsage();
    return 1;
  }
  return 0;
}
}  // namespace dreal

namespace {
void HandleSigInt(const int) {
  // Properly exit so that we can see stat information produced by destructors
  // even if a user press C-c.
  std::exit(1);
}
}  // namespace

int main(int argc, const char* argv[]) {
  std::signal(SIGINT, HandleSigInt);
  dreal::MainProgram main_program{argc, argv};
  return main_program.Run();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <random>
#include <bitset>
#include <boost/test/unit_test.hpp>
#include <boost/range/irange.hpp>
#include <seastar/core/semaphore.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/thread.hh>

#include "seastarx.hh"
#include "tests/test-utils.hh"
#include "utils/flush_queue.hh"
#include "log.hh"

std::random_device rd;
std::default_random_engine e1(rd());

SEASTAR_TEST_CASE(test_queue_ordering_random_ops) {
    struct env {
        env(size_t n) : promises(n) {}

        utils::flush_queue<int> queue;
        std::vector<promise<>> promises;
        std::vector<int> result;
    };

    auto r = boost::irange(0, 100);

    return do_for_each(r, [](int) {
        constexpr size_t num_ops = 1000;

        auto e = make_lw_shared<env>(num_ops);

        int i = 0;
        for (auto& p : e->promises) {
            e->queue.run_with_ordered_post_op(i, [&p, i] {
                return p.get_future().then([i] {
                    return make_ready_future<int>(i);
                });
            }, [e](int i) {
                e->result.emplace_back(i);
            });
            ++i;
        }

        auto res = e->queue.wait_for_pending();

        std::uniform_int_distribution<size_t> dist(0, num_ops - 1);
        std::bitset<num_ops> set;

        while (!set.all()) {
            size_t i = dist(e1);
            if (!set.test(i)) {
                set[i] = true;
                e->promises[i].set_value();
            }
        }

        return res.then([e] {
            BOOST_CHECK_EQUAL(e->result.size(), e->promises.size());
            BOOST_REQUIRE(std::is_sorted(e->result.begin(), e->result.end()));
        }).finally([e] {
            return e->queue.close().finally([e] { });
        });
    });
}

SEASTAR_TEST_CASE(test_queue_ordering_multi_ops) {
    struct env {
        env() : sem(0) {}

        utils::flush_queue<int> queue;
        std::vector<int> result;
        semaphore sem;
        size_t n = 0;
    };

    auto r = boost::irange(0, 100);

    return do_for_each(r, [](int) {
        constexpr size_t num_ops = 1000;

        auto e = make_lw_shared<env>();

        std::uniform_int_distribution<size_t> dist(0, num_ops - 1);

        for (size_t k = 0; k < num_ops*10; ++k) {
            int i = dist(e1);

            if (e->queue.has_operation(i) || (!e->queue.empty() && e->queue.highest_key() < i)) {
                e->queue.run_with_ordered_post_op(i, [e, i] {
                    return e->sem.wait().then([i] {
                        return make_ready_future<int>(i);
                    });
                }, [e](int i) {
                    e->result.emplace_back(i);
                });
                ++e->n;
            }
        }

        auto res = e->queue.wait_for_pending();

        e->sem.signal(e->n);

        return res.then([e] {
            BOOST_CHECK_EQUAL(e->result.size(), e->n);
            BOOST_REQUIRE(std::is_sorted(e->result.begin(), e->result.end()));
        }).finally([e] {
            return e->queue.close().finally([e] { });
        });
    });
}

template<typename Func, typename Post, typename Then>
static future<> test_propagation(bool propagate, Func&& func, Post&& post, Then&& thn, bool want_except_in_run, bool want_except_in_wait) {
    auto queue = ::make_shared<utils::flush_queue<int>>(propagate);
    auto sem = ::make_shared<semaphore>(0);
    auto xr = ::make_shared<bool>(false);
    auto xw = ::make_shared<bool>(false);

    auto f1 = queue->run_with_ordered_post_op(0, [sem, func = std::forward<Func>(func)]() mutable {
        return sem->wait().then(std::forward<Func>(func));
    }, std::forward<Post>(post)).handle_exception([xr](auto p) {
        *xr = true;
    }).discard_result();

    auto f2 = queue->wait_for_pending(0).then(std::forward<Then>(thn)).handle_exception([xw](auto p) {
        *xw = true;
    }).discard_result();

    sem->signal();

    return seastar::when_all_succeed(std::move(f1), std::move(f2)).finally([sem, queue, want_except_in_run, want_except_in_wait, xr, xw] {
        BOOST_CHECK_EQUAL(want_except_in_run, *xr);
        BOOST_CHECK_EQUAL(want_except_in_wait, *xw);
    }).finally([queue] {
        return queue->close().finally([queue] { });
    });
}

SEASTAR_TEST_CASE(test_propagate_exception_in_op) {
    return test_propagation(true, // propagate exception to waiter
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in op
                    [] { BOOST_FAIL("should not reach (1)"); }, // should not reach post
                    [] { BOOST_FAIL("should not reach (2)"); }, // should not reach waiter "then"
                    true,
                    true
                    );
}

SEASTAR_TEST_CASE(test_propagate_exception_in_post) {
    return test_propagation(true, // propagate exception to waiter
                    [] {}, // ok func
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in post
                    [] { BOOST_FAIL("should not reach"); }, // should not reach waiter "then"
                    true,
                    true
    );
}

SEASTAR_TEST_CASE(test_no_propagate_exception_in_op) {
    return test_propagation(false, // do not propagate exception to waiter
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in op
                    [] { BOOST_FAIL("should not reach"); }, // should not reach post
                    [] {}, // should reach waiter "then"
                    true,
                    false
                    );
}

SEASTAR_TEST_CASE(test_no_propagate_exception_in_post) {
    return test_propagation(false, // do not propagate exception to waiter
                    [] {}, // ok func
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in post
                    [] {}, // should reach waiter "then"
                    true,
                    false
                    );
}
<commit_msg>tests: flush_queue_test: de-template<commit_after>/*
 * Copyright 2015 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <random>
#include <bitset>
#include <boost/test/unit_test.hpp>
#include <boost/range/irange.hpp>
#include <seastar/core/semaphore.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/thread.hh>

#include "seastarx.hh"
#include "tests/test-utils.hh"
#include "utils/flush_queue.hh"
#include "log.hh"

std::random_device rd;
std::default_random_engine e1(rd());

SEASTAR_TEST_CASE(test_queue_ordering_random_ops) {
    struct env {
        env(size_t n) : promises(n) {}

        utils::flush_queue<int> queue;
        std::vector<promise<>> promises;
        std::vector<int> result;
    };

    auto r = boost::irange(0, 100);

    return do_for_each(r, [](int) {
        constexpr size_t num_ops = 1000;

        auto e = make_lw_shared<env>(num_ops);

        int i = 0;
        for (auto& p : e->promises) {
            e->queue.run_with_ordered_post_op(i, [&p, i] {
                return p.get_future().then([i] {
                    return make_ready_future<int>(i);
                });
            }, [e](int i) {
                e->result.emplace_back(i);
            });
            ++i;
        }

        auto res = e->queue.wait_for_pending();

        std::uniform_int_distribution<size_t> dist(0, num_ops - 1);
        std::bitset<num_ops> set;

        while (!set.all()) {
            size_t i = dist(e1);
            if (!set.test(i)) {
                set[i] = true;
                e->promises[i].set_value();
            }
        }

        return res.then([e] {
            BOOST_CHECK_EQUAL(e->result.size(), e->promises.size());
            BOOST_REQUIRE(std::is_sorted(e->result.begin(), e->result.end()));
        }).finally([e] {
            return e->queue.close().finally([e] { });
        });
    });
}

SEASTAR_TEST_CASE(test_queue_ordering_multi_ops) {
    struct env {
        env() : sem(0) {}

        utils::flush_queue<int> queue;
        std::vector<int> result;
        semaphore sem;
        size_t n = 0;
    };

    auto r = boost::irange(0, 100);

    return do_for_each(r, [](int) {
        constexpr size_t num_ops = 1000;

        auto e = make_lw_shared<env>();

        std::uniform_int_distribution<size_t> dist(0, num_ops - 1);

        for (size_t k = 0; k < num_ops*10; ++k) {
            int i = dist(e1);

            if (e->queue.has_operation(i) || (!e->queue.empty() && e->queue.highest_key() < i)) {
                e->queue.run_with_ordered_post_op(i, [e, i] {
                    return e->sem.wait().then([i] {
                        return make_ready_future<int>(i);
                    });
                }, [e](int i) {
                    e->result.emplace_back(i);
                });
                ++e->n;
            }
        }

        auto res = e->queue.wait_for_pending();

        e->sem.signal(e->n);

        return res.then([e] {
            BOOST_CHECK_EQUAL(e->result.size(), e->n);
            BOOST_REQUIRE(std::is_sorted(e->result.begin(), e->result.end()));
        }).finally([e] {
            return e->queue.close().finally([e] { });
        });
    });
}

static future<> test_propagation(bool propagate,
        noncopyable_function<future<> ()> func,
        noncopyable_function<future<> ()> post,
        noncopyable_function<void ()> thn,
        bool want_except_in_run, bool want_except_in_wait) {
    auto queue = ::make_shared<utils::flush_queue<int>>(propagate);
    auto sem = ::make_shared<semaphore>(0);
    auto xr = ::make_shared<bool>(false);
    auto xw = ::make_shared<bool>(false);

    auto f1 = queue->run_with_ordered_post_op(0, [sem, func = std::move(func)]() mutable {
        return sem->wait().then(std::move(func));
    }, std::move(post)).handle_exception([xr](auto p) {
        *xr = true;
    }).discard_result();

    auto f2 = queue->wait_for_pending(0).then(std::move(thn)).handle_exception([xw](auto p) {
        *xw = true;
    }).discard_result();

    sem->signal();

    return seastar::when_all_succeed(std::move(f1), std::move(f2)).finally([sem, queue, want_except_in_run, want_except_in_wait, xr, xw] {
        BOOST_CHECK_EQUAL(want_except_in_run, *xr);
        BOOST_CHECK_EQUAL(want_except_in_wait, *xw);
    }).finally([queue] {
        return queue->close().finally([queue] { });
    });
}

SEASTAR_TEST_CASE(test_propagate_exception_in_op) {
    return test_propagation(true, // propagate exception to waiter
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in op
                    [] { BOOST_FAIL("should not reach (1)"); return make_ready_future(); }, // should not reach post
                    [] { BOOST_FAIL("should not reach (2)"); }, // should not reach waiter "then"
                    true,
                    true
                    );
}

SEASTAR_TEST_CASE(test_propagate_exception_in_post) {
    return test_propagation(true, // propagate exception to waiter
                    [] { return make_ready_future(); }, // ok func
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in post
                    [] { BOOST_FAIL("should not reach"); }, // should not reach waiter "then"
                    true,
                    true
    );
}

SEASTAR_TEST_CASE(test_no_propagate_exception_in_op) {
    return test_propagation(false, // do not propagate exception to waiter
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in op
                    [] { BOOST_FAIL("should not reach"); return make_ready_future(); }, // should not reach post
                    [] {}, // should reach waiter "then"
                    true,
                    false
                    );
}

SEASTAR_TEST_CASE(test_no_propagate_exception_in_post) {
    return test_propagation(false, // do not propagate exception to waiter
                    [] { return make_ready_future(); }, // ok func
                    [] { return make_exception_future(std::runtime_error("hej")); }, // ex in post
                    [] {}, // should reach waiter "then"
                    true,
                    false
                    );
}
<|endoftext|>


<commit_before>#include <LuaContext.hpp>
#include <gtest/gtest.h>

TEST(FunctionsWrite, NativeFunctions) {
	struct Foo {
		static int increment(int x)
		{
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", &Foo::increment);
	context.writeFunction<int (int)>("g", &Foo::increment);
	context.writeFunction("h", &Foo::increment);

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, FunctionObjects) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		double operator()(double) {
			EXPECT_TRUE(false);
			return 0;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
}

TEST(FunctionsWrite, FunctionObjectsConst) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		int operator()(int x) const {
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
}

TEST(FunctionsWrite, FunctionObjectsAutodetect) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});
	context.writeFunction("h", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, Lambdas) {
	LuaContext context;

	const auto lambda = [](int x) { return x + 1; };
	context.writeVariable("f", std::function<int (int)>(lambda));
	context.writeFunction<int (int)>("g", lambda);
	context.writeFunction("h", lambda);

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, DestructorCalled) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		std::shared_ptr<char> dummy;
	};

	auto foo = Foo{ std::make_shared<char>() };
	std::weak_ptr<char> dummy = foo.dummy;

	auto context = std::make_shared<LuaContext>();
	context->writeFunction("f", foo);
	foo.dummy.reset();

	EXPECT_FALSE(dummy.expired());
	context.reset();
	EXPECT_TRUE(dummy.expired());
}

TEST(FunctionsWrite, ReturningMultipleValues) {
	LuaContext context;

	context.writeFunction("f", [](int x) { return std::make_tuple(x, x+1, "hello"); });
	context.executeCode("a, b, c = f(2)");

	EXPECT_EQ(2, context.readVariable<int>("a"));
	EXPECT_EQ(3, context.readVariable<int>("b"));
	EXPECT_EQ("hello", context.readVariable<std::string>("c"));
}
<commit_msg>Added test for polymorphic functions<commit_after>#include <LuaContext.hpp>
#include <gtest/gtest.h>

TEST(FunctionsWrite, NativeFunctions) {
	struct Foo {
		static int increment(int x)
		{
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", &Foo::increment);
	context.writeFunction<int (int)>("g", &Foo::increment);
	context.writeFunction("h", &Foo::increment);

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, FunctionObjects) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		double operator()(double) {
			EXPECT_TRUE(false);
			return 0;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
}

TEST(FunctionsWrite, FunctionObjectsConst) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		int operator()(int x) const {
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
}

TEST(FunctionsWrite, FunctionObjectsAutodetect) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}
	};

	LuaContext context;

	context.writeVariable("f", std::function<int (int)>(Foo{}));
	context.writeFunction<int (int)>("g", Foo{});
	context.writeFunction("h", Foo{});

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, Lambdas) {
	LuaContext context;

	const auto lambda = [](int x) { return x + 1; };
	context.writeVariable("f", std::function<int (int)>(lambda));
	context.writeFunction<int (int)>("g", lambda);
	context.writeFunction("h", lambda);

	EXPECT_EQ(3, context.executeCode<int>("return f(2)"));
	EXPECT_EQ(13, context.executeCode<int>("return g(12)"));
	EXPECT_EQ(9, context.executeCode<int>("return h(8)"));
}

TEST(FunctionsWrite, DestructorCalled) {
	struct Foo {
		int operator()(int x) {
			return x + 1;
		}

		std::shared_ptr<char> dummy;
	};

	auto foo = Foo{ std::make_shared<char>() };
	std::weak_ptr<char> dummy = foo.dummy;

	auto context = std::make_shared<LuaContext>();
	context->writeFunction("f", foo);
	foo.dummy.reset();

	EXPECT_FALSE(dummy.expired());
	context.reset();
	EXPECT_TRUE(dummy.expired());
}

TEST(FunctionsWrite, ReturningMultipleValues) {
	LuaContext context;

	context.writeFunction("f", [](int x) { return std::make_tuple(x, x+1, "hello"); });
	context.executeCode("a, b, c = f(2)");

	EXPECT_EQ(2, context.readVariable<int>("a"));
	EXPECT_EQ(3, context.readVariable<int>("b"));
	EXPECT_EQ("hello", context.readVariable<std::string>("c"));
}

TEST(FunctionsWrite, PolymorphicFunctions) {
	LuaContext context;

	context.writeFunction("f",
		[](boost::variant<int,bool,std::string> x) -> std::string
		{
			if (x.which() == 0)
				return "int";
			else if (x.which() == 1)
				return "bool";
			else
				return "string";
		}
	);

	EXPECT_EQ("int", context.executeCode<std::string>("return f(2)"));
	EXPECT_EQ("bool", context.executeCode<std::string>("return f(true)"));
	EXPECT_EQ("string", context.executeCode<std::string>("return f('test')"));
}
<|endoftext|>


<commit_before>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP(".proton.server.searchabledocsubdb");

#include "searchabledocsubdb.h"
#include <vespa/searchcore/proton/attribute/attribute_writer.h>
#include <vespa/searchcore/proton/flushengine/threadedflushtarget.h>
#include <vespa/searchcore/proton/index/index_manager_initializer.h>
#include <vespa/searchcore/proton/index/index_writer.h>
#include <vespa/searchcore/proton/metrics/legacy_documentdb_metrics.h>
#include <vespa/searchcore/proton/metrics/metricswireservice.h>
#include <vespa/searchcorespi/plugin/iindexmanagerfactory.h>
#include <vespa/searchlib/common/indexmetainfo.h>
#include <vespa/vespalib/io/fileutil.h>
#include <vespa/vespalib/util/closuretask.h>

using vespa::config::search::AttributesConfig;
using vespa::config::search::RankProfilesConfig;
using vespa::config::search::core::ProtonConfig;
using proton::matching::MatchingStats;
using proton::matching::SessionManager;
using search::AttributeGuard;
using search::AttributeVector;
using search::GrowStrategy;
using search::TuneFileDocumentDB;
using search::index::Schema;
using search::SerialNum;
using searchcorespi::IndexManagerConfig;
using searchcorespi::index::IndexMaintainerConfig;
using searchcorespi::index::IndexMaintainerContext;
using vespalib::IllegalStateException;
using vespalib::ThreadStackExecutorBase;
using namespace searchcorespi;

namespace proton {

SearchableDocSubDB::SearchableDocSubDB(const Config &cfg,
                                       const Context &ctx)
    : FastAccessDocSubDB(cfg._fastUpdCfg,
                         ctx._fastUpdCtx),
      IIndexManager::Reconfigurer(),
      _indexMgr(),
      _indexWriter(),
      _rSearchView(),
      _rFeedView(),
      _configurer(_iSummaryMgr, _rSearchView, _rFeedView, ctx._queryLimiter, ctx._clock,
                  getSubDbName(), ctx._fastUpdCtx._storeOnlyCtx._owner.getDistributionKey()),
      _numSearcherThreads(cfg._numSearcherThreads),
      _warmupExecutor(ctx._warmupExecutor)
{
}

SearchableDocSubDB::~SearchableDocSubDB()
{
    // XXX: Disk index wrappers should not live longer than index manager
    // which owns map of active disk indexes.
    clearViews();
}

void
SearchableDocSubDB::syncViews()
{
    _iSearchView.set(_rSearchView.get());
    _iFeedView.set(_rFeedView.get());
    _owner.syncFeedView();
}

SerialNum
SearchableDocSubDB::getOldestFlushedSerial()
{
    SerialNum lowest(Parent::getOldestFlushedSerial());
    lowest = std::min(lowest, _indexMgr->getFlushedSerialNum());
    return lowest;
}

SerialNum
SearchableDocSubDB::getNewestFlushedSerial()
{
    SerialNum highest(Parent::getNewestFlushedSerial());
    highest = std::max(highest, _indexMgr->getFlushedSerialNum());
    return highest;
}

initializer::InitializerTask::SP
SearchableDocSubDB::
createIndexManagerInitializer(const DocumentDBConfig &configSnapshot,
                              const Schema::SP &unionSchema,
                              const ProtonConfig::Index &indexCfg,
                              std::shared_ptr<searchcorespi::IIndexManager::SP> indexManager) const
{
    Schema::SP schema(configSnapshot.getSchemaSP());
    vespalib::string vespaIndexDir(_baseDir + "/index");
    // Note: const_cast for reconfigurer role
    return std::make_shared<IndexManagerInitializer>
        (vespaIndexDir,
         indexCfg.warmup.time,
         indexCfg.maxflushed,
         indexCfg.cache.size,
         *schema,
         *unionSchema,
         const_cast<SearchableDocSubDB &>(*this),
         _writeService,
         _warmupExecutor,
         configSnapshot.getTuneFileDocumentDBSP()->_index,
         configSnapshot.getTuneFileDocumentDBSP()->_attr,
         _fileHeaderContext,
         indexManager);
}

void
SearchableDocSubDB::setupIndexManager(searchcorespi::IIndexManager::SP
                                      indexManager)
{
    _indexMgr = indexManager;
    _indexWriter.reset(new IndexWriter(_indexMgr));
}

DocumentSubDbInitializer::UP
SearchableDocSubDB::
createInitializer(const DocumentDBConfig &configSnapshot,
                  SerialNum configSerialNum,
                  const Schema::SP &unionSchema,
                  const ProtonConfig::Summary &protonSummaryCfg,
                  const ProtonConfig::Index &indexCfg) const
{
    auto result = Parent::createInitializer(configSnapshot,
                                            configSerialNum,
                                            unionSchema,
                                            protonSummaryCfg,
                                            indexCfg);
    auto indexTask = createIndexManagerInitializer(configSnapshot,
                                                   unionSchema,
                                                   indexCfg,
                                                   result->writableResult().
                                                   writableIndexManager());
    result->addDependency(indexTask);
    return result;
}

void
SearchableDocSubDB::setup(const DocumentSubDbInitializerResult &initResult)
{
    Parent::setup(initResult);
    setupIndexManager(initResult.indexManager());
    _docIdLimit.set(_dms->getCommittedDocIdLimit());
}

void
SearchableDocSubDB::
reconfigureMatchingMetrics(const RankProfilesConfig &cfg)
{
    _metricsWireService.cleanRankProfiles(_metrics);
    for (const auto &profile : cfg.rankprofile) {
        search::fef::Properties properties;
        for (const auto &property : profile.fef.property) {
            properties.add(property.name,
                           property.value);
        }
        size_t numDocIdPartitions = search::fef::indexproperties::matching::NumThreadsPerSearch::lookup(properties);
        _metricsWireService.addRankProfile(_metrics,
                                           profile.name,
                                           numDocIdPartitions);
    }
}

IReprocessingTask::List
SearchableDocSubDB::applyConfig(const DocumentDBConfig &newConfigSnapshot,
                                const DocumentDBConfig &oldConfigSnapshot,
                                SerialNum serialNum,
                                const ReconfigParams params)
{
    IReprocessingTask::List tasks;
    updateLidReuseDelayer(&newConfigSnapshot);
    if (params.shouldMatchersChange() && _addMetrics) {
        reconfigureMatchingMetrics(newConfigSnapshot.getRankProfilesConfig());
    }
    if (params.shouldAttributeManagerChange()) {
        proton::IAttributeManager::SP oldMgr = getAttributeManager();
        AttributeCollectionSpec::UP attrSpec =
            createAttributeSpec(newConfigSnapshot.getAttributesConfig(), serialNum);
        IReprocessingInitializer::UP initializer =
                _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, *attrSpec, params);
        if (initializer.get() != nullptr && initializer->hasReprocessors()) {
            tasks.push_back(IReprocessingTask::SP(createReprocessingTask(*initializer,
                    newConfigSnapshot.getDocumentTypeRepoSP()).release()));
        }
        proton::IAttributeManager::SP newMgr = getAttributeManager();
        if (_addMetrics) {
            reconfigureAttributeMetrics(*newMgr, *oldMgr);
        }
    } else {
        _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, params);
    }
    syncViews();
    return tasks;
}

void
SearchableDocSubDB::initViews(const DocumentDBConfig &configSnapshot,
                              const SessionManager::SP &sessionManager)
{
    assert(_writeService.master().isCurrentThread());

    AttributeManager::SP attrMgr = getAndResetInitAttributeManager();
    const Schema::SP &schema = configSnapshot.getSchemaSP();
    const IIndexManager::SP &indexMgr = getIndexManager();
    Matchers::SP matchers(_configurer.
                          createMatchers(schema,
                                  configSnapshot.getRankProfilesConfig()).
                          release());
    MatchView::SP matchView(new MatchView(matchers,
                                          indexMgr->getSearchable(),
                                          attrMgr,
                                          sessionManager,
                                          _metaStoreCtx,
                                          _docIdLimit));
    _rSearchView.set(SearchView::SP(
                              new SearchView(
                                      getSummaryManager()->createSummarySetup(
                                              configSnapshot.getSummaryConfig(),
                                              configSnapshot.getSummarymapConfig(),
                                              configSnapshot.getJuniperrcConfig(),
                                              configSnapshot.getDocumentTypeRepoSP(),
                                              matchView->getAttributeManager()),
                                      matchView)));

    IAttributeWriter::SP attrWriter(new AttributeWriter(attrMgr));
    {
        vespalib::LockGuard guard(_configLock);
        initFeedView(attrWriter, configSnapshot);
    }
    if (_addMetrics) {
        reconfigureMatchingMetrics(configSnapshot.getRankProfilesConfig());
    }
}

void
SearchableDocSubDB::initFeedView(const IAttributeWriter::SP &attrWriter,
                                 const DocumentDBConfig &configSnapshot)
{
    assert(_writeService.master().isCurrentThread());
    SearchableFeedView::UP feedView(new SearchableFeedView(getStoreOnlyFeedViewContext(configSnapshot),
            getFeedViewPersistentParams(),
            FastAccessFeedView::Context(attrWriter, _docIdLimit),
            SearchableFeedView::Context(getIndexWriter())));

    // XXX: Not exception safe.
    _rFeedView.set(SearchableFeedView::SP(feedView.release()));
    syncViews();
}

/**
 * Handle reconfigure caused by index manager changing state.
 *
 * Flush engine is disabled (for all document dbs) during initial replay and
 * recovery feed modes, the flush engine has not started.  For a resurrected
 * document type, flushing might occur during replay.
 */
bool
SearchableDocSubDB::
reconfigure(vespalib::Closure0<bool>::UP closure)
{
    assert(_writeService.master().isCurrentThread());

    _writeService.sync();

    // Everything should be quiet now.

    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();

    bool ret = true;

    if (closure.get() != NULL)
        ret = closure->call();	// Perform index manager reconfiguration now
    reconfigureIndexSearchable();
    return ret;
}

void
SearchableDocSubDB::reconfigureIndexSearchable()
{
    vespalib::LockGuard guard(_configLock);
    // Create new views as needed.
    _configurer.reconfigureIndexSearchable();
    // Activate new feed view at once
    syncViews();
}

IFlushTarget::List
SearchableDocSubDB::getFlushTargetsInternal()
{
    IFlushTarget::List ret(Parent::getFlushTargetsInternal());

    IFlushTarget::List tmp = _indexMgr->getFlushTargets();
    ret.insert(ret.end(), tmp.begin(), tmp.end());

    return ret;
}

void
SearchableDocSubDB::wipeHistory(SerialNum wipeSerial,
                                const Schema &newHistorySchema,
                                const Schema &wipeSchema)
{
    assert(_writeService.master().isCurrentThread());
    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();
    _indexMgr->wipeHistory(wipeSerial, newHistorySchema);
    reconfigureIndexSearchable();
    getAttributeManager()->wipeHistory(wipeSchema);
}

void
SearchableDocSubDB::setIndexSchema(const Schema::SP &schema,
                                   const Schema::SP &fusionSchema)
{
    assert(_writeService.master().isCurrentThread());

    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();

    _indexMgr->setSchema(*schema, *fusionSchema);
    reconfigureIndexSearchable();
}

size_t
SearchableDocSubDB::getNumActiveDocs() const
{
    return _metaStoreCtx->getReadGuard()->get().getNumActiveLids();
}

search::SearchableStats
SearchableDocSubDB::getSearchableStats() const
{
    return _indexMgr->getSearchableStats();
}

IDocumentRetriever::UP
SearchableDocSubDB::getDocumentRetriever()
{
    return IDocumentRetriever::UP(new FastAccessDocumentRetriever(_rFeedView.get(), _rSearchView.get()->getAttributeManager()));
}

MatchingStats
SearchableDocSubDB::getMatcherStats(const vespalib::string &rankProfile) const
{
    return _rSearchView.get()->getMatcherStats(rankProfile);
}

void
SearchableDocSubDB::updateLidReuseDelayer(const LidReuseDelayerConfig &config)
{
    Parent::updateLidReuseDelayer(config);
    /*
     * The lid reuse delayer should not have any pending lids stored at this
     * time, since DocumentDB::applyConfig() calls forceCommit() on the
     * feed view before applying the new config to the sub dbs.
     */
    _lidReuseDelayer->setHasIndexedFields(config.hasIndexedFields());
}

} // namespace proton
<commit_msg>Include fast_access_document_retriever.h<commit_after>// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include <vespa/fastos/fastos.h>
#include <vespa/log/log.h>
LOG_SETUP(".proton.server.searchabledocsubdb");

#include "searchabledocsubdb.h"
#include "fast_access_document_retriever.h"
#include <vespa/searchcore/proton/attribute/attribute_writer.h>
#include <vespa/searchcore/proton/flushengine/threadedflushtarget.h>
#include <vespa/searchcore/proton/index/index_manager_initializer.h>
#include <vespa/searchcore/proton/index/index_writer.h>
#include <vespa/searchcore/proton/metrics/legacy_documentdb_metrics.h>
#include <vespa/searchcore/proton/metrics/metricswireservice.h>
#include <vespa/searchcorespi/plugin/iindexmanagerfactory.h>
#include <vespa/searchlib/common/indexmetainfo.h>
#include <vespa/vespalib/io/fileutil.h>
#include <vespa/vespalib/util/closuretask.h>

using vespa::config::search::AttributesConfig;
using vespa::config::search::RankProfilesConfig;
using vespa::config::search::core::ProtonConfig;
using proton::matching::MatchingStats;
using proton::matching::SessionManager;
using search::AttributeGuard;
using search::AttributeVector;
using search::GrowStrategy;
using search::TuneFileDocumentDB;
using search::index::Schema;
using search::SerialNum;
using searchcorespi::IndexManagerConfig;
using searchcorespi::index::IndexMaintainerConfig;
using searchcorespi::index::IndexMaintainerContext;
using vespalib::IllegalStateException;
using vespalib::ThreadStackExecutorBase;
using namespace searchcorespi;

namespace proton {

SearchableDocSubDB::SearchableDocSubDB(const Config &cfg,
                                       const Context &ctx)
    : FastAccessDocSubDB(cfg._fastUpdCfg,
                         ctx._fastUpdCtx),
      IIndexManager::Reconfigurer(),
      _indexMgr(),
      _indexWriter(),
      _rSearchView(),
      _rFeedView(),
      _configurer(_iSummaryMgr, _rSearchView, _rFeedView, ctx._queryLimiter, ctx._clock,
                  getSubDbName(), ctx._fastUpdCtx._storeOnlyCtx._owner.getDistributionKey()),
      _numSearcherThreads(cfg._numSearcherThreads),
      _warmupExecutor(ctx._warmupExecutor)
{
}

SearchableDocSubDB::~SearchableDocSubDB()
{
    // XXX: Disk index wrappers should not live longer than index manager
    // which owns map of active disk indexes.
    clearViews();
}

void
SearchableDocSubDB::syncViews()
{
    _iSearchView.set(_rSearchView.get());
    _iFeedView.set(_rFeedView.get());
    _owner.syncFeedView();
}

SerialNum
SearchableDocSubDB::getOldestFlushedSerial()
{
    SerialNum lowest(Parent::getOldestFlushedSerial());
    lowest = std::min(lowest, _indexMgr->getFlushedSerialNum());
    return lowest;
}

SerialNum
SearchableDocSubDB::getNewestFlushedSerial()
{
    SerialNum highest(Parent::getNewestFlushedSerial());
    highest = std::max(highest, _indexMgr->getFlushedSerialNum());
    return highest;
}

initializer::InitializerTask::SP
SearchableDocSubDB::
createIndexManagerInitializer(const DocumentDBConfig &configSnapshot,
                              const Schema::SP &unionSchema,
                              const ProtonConfig::Index &indexCfg,
                              std::shared_ptr<searchcorespi::IIndexManager::SP> indexManager) const
{
    Schema::SP schema(configSnapshot.getSchemaSP());
    vespalib::string vespaIndexDir(_baseDir + "/index");
    // Note: const_cast for reconfigurer role
    return std::make_shared<IndexManagerInitializer>
        (vespaIndexDir,
         indexCfg.warmup.time,
         indexCfg.maxflushed,
         indexCfg.cache.size,
         *schema,
         *unionSchema,
         const_cast<SearchableDocSubDB &>(*this),
         _writeService,
         _warmupExecutor,
         configSnapshot.getTuneFileDocumentDBSP()->_index,
         configSnapshot.getTuneFileDocumentDBSP()->_attr,
         _fileHeaderContext,
         indexManager);
}

void
SearchableDocSubDB::setupIndexManager(searchcorespi::IIndexManager::SP
                                      indexManager)
{
    _indexMgr = indexManager;
    _indexWriter.reset(new IndexWriter(_indexMgr));
}

DocumentSubDbInitializer::UP
SearchableDocSubDB::
createInitializer(const DocumentDBConfig &configSnapshot,
                  SerialNum configSerialNum,
                  const Schema::SP &unionSchema,
                  const ProtonConfig::Summary &protonSummaryCfg,
                  const ProtonConfig::Index &indexCfg) const
{
    auto result = Parent::createInitializer(configSnapshot,
                                            configSerialNum,
                                            unionSchema,
                                            protonSummaryCfg,
                                            indexCfg);
    auto indexTask = createIndexManagerInitializer(configSnapshot,
                                                   unionSchema,
                                                   indexCfg,
                                                   result->writableResult().
                                                   writableIndexManager());
    result->addDependency(indexTask);
    return result;
}

void
SearchableDocSubDB::setup(const DocumentSubDbInitializerResult &initResult)
{
    Parent::setup(initResult);
    setupIndexManager(initResult.indexManager());
    _docIdLimit.set(_dms->getCommittedDocIdLimit());
}

void
SearchableDocSubDB::
reconfigureMatchingMetrics(const RankProfilesConfig &cfg)
{
    _metricsWireService.cleanRankProfiles(_metrics);
    for (const auto &profile : cfg.rankprofile) {
        search::fef::Properties properties;
        for (const auto &property : profile.fef.property) {
            properties.add(property.name,
                           property.value);
        }
        size_t numDocIdPartitions = search::fef::indexproperties::matching::NumThreadsPerSearch::lookup(properties);
        _metricsWireService.addRankProfile(_metrics,
                                           profile.name,
                                           numDocIdPartitions);
    }
}

IReprocessingTask::List
SearchableDocSubDB::applyConfig(const DocumentDBConfig &newConfigSnapshot,
                                const DocumentDBConfig &oldConfigSnapshot,
                                SerialNum serialNum,
                                const ReconfigParams params)
{
    IReprocessingTask::List tasks;
    updateLidReuseDelayer(&newConfigSnapshot);
    if (params.shouldMatchersChange() && _addMetrics) {
        reconfigureMatchingMetrics(newConfigSnapshot.getRankProfilesConfig());
    }
    if (params.shouldAttributeManagerChange()) {
        proton::IAttributeManager::SP oldMgr = getAttributeManager();
        AttributeCollectionSpec::UP attrSpec =
            createAttributeSpec(newConfigSnapshot.getAttributesConfig(), serialNum);
        IReprocessingInitializer::UP initializer =
                _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, *attrSpec, params);
        if (initializer.get() != nullptr && initializer->hasReprocessors()) {
            tasks.push_back(IReprocessingTask::SP(createReprocessingTask(*initializer,
                    newConfigSnapshot.getDocumentTypeRepoSP()).release()));
        }
        proton::IAttributeManager::SP newMgr = getAttributeManager();
        if (_addMetrics) {
            reconfigureAttributeMetrics(*newMgr, *oldMgr);
        }
    } else {
        _configurer.reconfigure(newConfigSnapshot, oldConfigSnapshot, params);
    }
    syncViews();
    return tasks;
}

void
SearchableDocSubDB::initViews(const DocumentDBConfig &configSnapshot,
                              const SessionManager::SP &sessionManager)
{
    assert(_writeService.master().isCurrentThread());

    AttributeManager::SP attrMgr = getAndResetInitAttributeManager();
    const Schema::SP &schema = configSnapshot.getSchemaSP();
    const IIndexManager::SP &indexMgr = getIndexManager();
    Matchers::SP matchers(_configurer.
                          createMatchers(schema,
                                  configSnapshot.getRankProfilesConfig()).
                          release());
    MatchView::SP matchView(new MatchView(matchers,
                                          indexMgr->getSearchable(),
                                          attrMgr,
                                          sessionManager,
                                          _metaStoreCtx,
                                          _docIdLimit));
    _rSearchView.set(SearchView::SP(
                              new SearchView(
                                      getSummaryManager()->createSummarySetup(
                                              configSnapshot.getSummaryConfig(),
                                              configSnapshot.getSummarymapConfig(),
                                              configSnapshot.getJuniperrcConfig(),
                                              configSnapshot.getDocumentTypeRepoSP(),
                                              matchView->getAttributeManager()),
                                      matchView)));

    IAttributeWriter::SP attrWriter(new AttributeWriter(attrMgr));
    {
        vespalib::LockGuard guard(_configLock);
        initFeedView(attrWriter, configSnapshot);
    }
    if (_addMetrics) {
        reconfigureMatchingMetrics(configSnapshot.getRankProfilesConfig());
    }
}

void
SearchableDocSubDB::initFeedView(const IAttributeWriter::SP &attrWriter,
                                 const DocumentDBConfig &configSnapshot)
{
    assert(_writeService.master().isCurrentThread());
    SearchableFeedView::UP feedView(new SearchableFeedView(getStoreOnlyFeedViewContext(configSnapshot),
            getFeedViewPersistentParams(),
            FastAccessFeedView::Context(attrWriter, _docIdLimit),
            SearchableFeedView::Context(getIndexWriter())));

    // XXX: Not exception safe.
    _rFeedView.set(SearchableFeedView::SP(feedView.release()));
    syncViews();
}

/**
 * Handle reconfigure caused by index manager changing state.
 *
 * Flush engine is disabled (for all document dbs) during initial replay and
 * recovery feed modes, the flush engine has not started.  For a resurrected
 * document type, flushing might occur during replay.
 */
bool
SearchableDocSubDB::
reconfigure(vespalib::Closure0<bool>::UP closure)
{
    assert(_writeService.master().isCurrentThread());

    _writeService.sync();

    // Everything should be quiet now.

    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();

    bool ret = true;

    if (closure.get() != NULL)
        ret = closure->call();	// Perform index manager reconfiguration now
    reconfigureIndexSearchable();
    return ret;
}

void
SearchableDocSubDB::reconfigureIndexSearchable()
{
    vespalib::LockGuard guard(_configLock);
    // Create new views as needed.
    _configurer.reconfigureIndexSearchable();
    // Activate new feed view at once
    syncViews();
}

IFlushTarget::List
SearchableDocSubDB::getFlushTargetsInternal()
{
    IFlushTarget::List ret(Parent::getFlushTargetsInternal());

    IFlushTarget::List tmp = _indexMgr->getFlushTargets();
    ret.insert(ret.end(), tmp.begin(), tmp.end());

    return ret;
}

void
SearchableDocSubDB::wipeHistory(SerialNum wipeSerial,
                                const Schema &newHistorySchema,
                                const Schema &wipeSchema)
{
    assert(_writeService.master().isCurrentThread());
    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();
    _indexMgr->wipeHistory(wipeSerial, newHistorySchema);
    reconfigureIndexSearchable();
    getAttributeManager()->wipeHistory(wipeSchema);
}

void
SearchableDocSubDB::setIndexSchema(const Schema::SP &schema,
                                   const Schema::SP &fusionSchema)
{
    assert(_writeService.master().isCurrentThread());

    SearchView::SP oldSearchView = _rSearchView.get();
    IFeedView::SP oldFeedView = _iFeedView.get();

    _indexMgr->setSchema(*schema, *fusionSchema);
    reconfigureIndexSearchable();
}

size_t
SearchableDocSubDB::getNumActiveDocs() const
{
    return _metaStoreCtx->getReadGuard()->get().getNumActiveLids();
}

search::SearchableStats
SearchableDocSubDB::getSearchableStats() const
{
    return _indexMgr->getSearchableStats();
}

IDocumentRetriever::UP
SearchableDocSubDB::getDocumentRetriever()
{
    return IDocumentRetriever::UP(new FastAccessDocumentRetriever(_rFeedView.get(), _rSearchView.get()->getAttributeManager()));
}

MatchingStats
SearchableDocSubDB::getMatcherStats(const vespalib::string &rankProfile) const
{
    return _rSearchView.get()->getMatcherStats(rankProfile);
}

void
SearchableDocSubDB::updateLidReuseDelayer(const LidReuseDelayerConfig &config)
{
    Parent::updateLidReuseDelayer(config);
    /*
     * The lid reuse delayer should not have any pending lids stored at this
     * time, since DocumentDB::applyConfig() calls forceCommit() on the
     * feed view before applying the new config to the sub dbs.
     */
    _lidReuseDelayer->setHasIndexedFields(config.hasIndexedFields());
}

} // namespace proton
<|endoftext|>


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

#include "testing/gtest/include/gtest/gtest.h"
#include "base/string_escape.h"

TEST(StringEscapeTest, JavascriptDoubleQuote) {
  static const char* kToEscape          = "\b\001aZ\"\\wee";
  static const char* kEscaped           = "\\b\\x01aZ\\\"\\\\wee";
  static const wchar_t* kUToEscape      = L"\b\x0001" L"a\x123fZ\"\\wee";
  static const char* kUEscaped          = "\\b\\x01a\\u123FZ\\\"\\\\wee";
  static const char* kUEscapedQuoted    = "\"\\b\\x01a\\u123FZ\\\"\\\\wee\"";

  std::string out;

  // Test wide unicode escaping
  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::wstring(kUToEscape), false, &out);
  ASSERT_EQ(std::string("testy: ") + kUEscaped, out);

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::wstring(kUToEscape), true, &out);
  ASSERT_EQ(std::string("testy: ") + kUEscapedQuoted, out);

  // Test null and high bit / negative unicode values
  std::wstring wstr(L"TeSt");
  wstr.push_back(0);
  wstr.push_back(0xffb1);
  wstr.push_back(0x00ff);

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(wstr, false, &out);
  ASSERT_EQ("testy: TeSt\\x00\\uFFB1\\xFF", out);

  // Test escaping of 7bit ascii
  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::string(kToEscape), false, &out);
  ASSERT_EQ(std::string("testy: ") + kEscaped, out);

  // Test null, non-printable, and non-7bit
  std::string str("TeSt");
  str.push_back(0);
  str.push_back(15);
  str.push_back(127);
  str.push_back(-16);
  str.push_back(-128);
  str.push_back('!');

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(str, false, &out);
  ASSERT_EQ("testy: TeSt\\x00\\x0F\\x7F\xf0\x80!", out);
}
<commit_msg>Add a few tests to string_escape improving code coverage.<commit_after>// Copyright 2008, Google Inc.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//    * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//    * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//    * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include "testing/gtest/include/gtest/gtest.h"
#include "base/string_escape.h"

TEST(StringEscapeTest, JavascriptDoubleQuote) {
  static const char* kToEscape          = "\b\001aZ\"\\wee";
  static const char* kEscaped           = "\\b\\x01aZ\\\"\\\\wee";
  static const char* kEscapedQuoted     = "\"\\b\\x01aZ\\\"\\\\wee\"";
  static const wchar_t* kUToEscape      = L"\b\x0001" L"a\x123fZ\"\\wee";
  static const char* kUEscaped          = "\\b\\x01a\\u123FZ\\\"\\\\wee";
  static const char* kUEscapedQuoted    = "\"\\b\\x01a\\u123FZ\\\"\\\\wee\"";

  std::string out;

  // Test wide unicode escaping
  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::wstring(kUToEscape), false, &out);
  ASSERT_EQ(std::string("testy: ") + kUEscaped, out);

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::wstring(kUToEscape), true, &out);
  ASSERT_EQ(std::string("testy: ") + kUEscapedQuoted, out);

  // Test null and high bit / negative unicode values
  std::wstring wstr(L"TeSt");
  wstr.push_back(0);
  wstr.push_back(0xffb1);
  wstr.push_back(0x00ff);

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(wstr, false, &out);
  ASSERT_EQ("testy: TeSt\\x00\\uFFB1\\xFF", out);

  // Test escaping of 7bit ascii
  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::string(kToEscape), false, &out);
  ASSERT_EQ(std::string("testy: ") + kEscaped, out);

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(std::string(kToEscape), true, &out);
  ASSERT_EQ(std::string("testy: ") + kEscapedQuoted, out);

  // Test null, non-printable, and non-7bit
  std::string str("TeSt");
  str.push_back(0);
  str.push_back(15);
  str.push_back(127);
  str.push_back(-16);
  str.push_back(-128);
  str.push_back('!');

  out = "testy: ";
  string_escape::JavascriptDoubleQuote(str, false, &out);
  ASSERT_EQ("testy: TeSt\\x00\\x0F\\x7F\xf0\x80!", out);

  // Test escape sequences
  out = "testy: ";
  string_escape::JavascriptDoubleQuote("a\b\f\n\r\t\v\1\\.\"z", false, &out);
  ASSERT_EQ("testy: a\\b\\f\\n\\r\\t\\v\\x01\\\\.\\\"z", out);
}
<|endoftext|>