<commit_before>#include "Generator/Generator.h"

#include "Config.h"
#include "Utils/Utils.h"
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include <getopt.h>
#include <cstdio>
#include <iostream>

/*! dalec

    The main compiler executable, responsible for organising the
    arguments for Generator, running Generator, and assembling/linking
    the results together using the system's compiler.
*/

using namespace dale;

static const char *options = "M:m:O:a:I:L:l:o:s:b:cdrR";

static bool
appearsToBeLib(const char *str)
{
    int len = strlen(str);
    if (len >= 2) {
        const char *end = str + (len - 2);
        if ((!strcmp(end, ".o")) || (!strcmp(end, ".a"))) {
            return true;
        }
    }
    return false;
}

std::string
joinWithPrefix (std::vector<const char*> strings,
                const std::string prefix, std::string buffer)
{
  for (std::vector<const char*>::iterator b = strings.begin (),
                                          e = strings.end ();
       b != e; buffer += " " + prefix + " " + (* b ++));

  return buffer;
}

int
main(int argc, char **argv)
{
    srand(time(NULL) + getpid());

    progname = argv[0];

    int opt;
    char optc;

    std::vector<const char*>
      input_files,
      input_link_files,
      compile_libs,
      run_libs,
      include_paths,
      run_paths,
      bitcode_paths,
      static_modules,
      module_paths;

    const char *output_path_arg = NULL;
    const char *module_name     = NULL;

    int produce  = ASM;
    int optlevel = 0;

    int produce_set      = 0;
    int no_linking       = 0;
    int debug            = 0;
    int no_dale_stdlib   = 0;
    int no_stdlib        = 0;
    int remove_macros    = 0;
    int no_common        = 0;
    int static_mods_all  = 0;
    int found_sm         = 0;
    int enable_cto       = 0;
    int version          = 0;
    int print_expansions = 0;

    int option_index         = 0;
    int forced_remove_macros = 0;

    static struct option long_options[] = {
        { "no-dale-stdlib",   no_argument,       &no_dale_stdlib,   1 },
        { "no-common",        no_argument,       &no_common,        1 },
        { "no-stdlib",        no_argument,       &no_stdlib,        1 },
        { "static-modules",   no_argument,       &static_mods_all,  1 },
        { "static-module",    required_argument, &found_sm,         1 },
        { "enable-cto",       no_argument,       &enable_cto,       1 },
        { "version",          no_argument,       &version,          1 },
        { "print-expansions", no_argument,       &print_expansions, 1 },
        { 0, 0, 0, 0 }
    };

    if (argc < 2) {
        error("no input files");
    }

    while ((opt = getopt_long(argc, argv, options,
                              long_options, &option_index)) != -1) {
        optc = (char) opt;

        switch (optc) {
            case 'o': {
                if (output_path_arg) {
                    error("an output path has already been specified");
                }
                output_path_arg = optarg;
                break;
            }
            case 'O': {
                optlevel = (optarg[0] - '0');
                if ((optlevel < 0) || (optlevel > 4)) {
                    error("invalid optimisation level");
                }
                break;
            }
            case 's': {
                produce_set = true;

                const char *type = optarg;
                if (!strcmp (type, "as")) produce = ASM;     else
                if (!strcmp (type, "ir")) produce = IR;      else
                if (!strcmp (type, "bc")) produce = BitCode; else
                  error ("unrecognised output file format");

                break;
            }
            case 'd': debug = 1;                                   break;
            case 'c': no_linking = 1;                              break;
            case 'r': remove_macros = 1; forced_remove_macros = 1; break;
            case 'R': remove_macros = 0; forced_remove_macros = 1; break;
            case 'I': include_paths.push_back(optarg);             break;
            case 'a': compile_libs.push_back(optarg);              break;
            case 'L': run_paths.push_back(optarg);                 break;
            case 'l': run_libs.push_back(optarg);                  break;
            case 'b': bitcode_paths.push_back(optarg);             break;
            case 'M': module_paths.push_back(optarg);              break;
            case 'm': module_name = optarg;                        break;
        };

        if (found_sm) {
            found_sm = 0;
            static_modules.push_back(optarg);
        }
    }

    if (version)
      std::cout << DALE_VERSION_MAJOR << "."
                << DALE_VERSION_MINOR << std::endl, exit (0);

    /* If the user wants an executable and has not specified either
     * way with respect to removing macros, then remove macros. */
    if (!no_linking && !produce_set && !forced_remove_macros) {
        remove_macros = 1;
    }

    /* Every argument after the options is treated as an input file.
     * Input files that end with .o or .a should go straight to the
     * linker. */
    while (optind != argc)
      {
        const char *input_file = argv [optind ++];

        (appearsToBeLib (input_file) ?
         input_link_files : input_files) .push_back (input_file);
      }
    if (input_files.size () == 0) error ("no input files");

    /* Set output_path. */
    std::string output_path;
    if (output_path_arg) output_path = output_path_arg;  // is given
    else  // otherwise construct it
      {
        output_path = input_files [0];  // leave the extension as is

        if (no_linking) output_path += ".o";
        else if (produce_set) output_path +=
                            ((produce == IR)      ? ".ll" :
                             (produce == ASM)     ? ".s"  :
                             (produce == BitCode) ? ".bc" :
                             ".unknown" );  // impossible, an error
        else output_path = "a.out";  // overwrite what was there
      }

    std::vector<std::string> so_paths;
    Generator generator;

    std::string intermediate_output_path =
      output_path + (produce_set ? "" : ".s");
    {
      FILE *output_file =
        fopen (intermediate_output_path.c_str (), "w");
      if (output_file == NULL) error ("unable to open %s for writing",
                                      intermediate_output_path.c_str (),
                                      true);
      if (! generator.run (&input_files,
                           &bitcode_paths,
                           &compile_libs,
                           &include_paths,
                           &module_paths,
                           &static_modules,
                           module_name,
                           debug,
                           produce,
                           optlevel,
                           remove_macros,
                           no_common,
                           no_dale_stdlib,
                           static_mods_all,
                           enable_cto,
                           print_expansions,
                           &so_paths,
                           output_file)) exit (1);
      if (fflush (output_file) != 0)
        error ("unable to flush the intermediate output file", true);
    }
    if (produce_set) exit (0);  // we're done

    // prepare the strings to sew the compile command with
    std::string input_file_str =
      joinWithPrefix (input_files, " ", "");
    std::string compile_lib_str =
      joinWithPrefix (compile_libs, "-l", "");
    std::string include_path_str =
      joinWithPrefix (include_paths, "-I", "");
    std::string run_path_str =
      joinWithPrefix (run_paths, "-L", "");
    std::string run_lib_str =
      joinWithPrefix (run_libs, "-l", "");
    std::string rpath_str = strcmp (SYSTEM_NAME, "Darwin") ?
      "" : joinWithPrefix (module_paths, "-rpath", "");

    std::string input_link_file_str =
      joinWithPrefix (input_link_files, " ", "");
    for (std::vector<std::string>::iterator b = so_paths.begin (),
                                            e = so_paths.end ();
         b != e; input_link_file_str += " " + (* b ++));

    // compose the compiler/linker command and execute it
    const char *aux = getenv ("DALE_CC_FLAGS");  // auxiliary options
    std::string compile_cmd = DALE_CC;
    if (no_stdlib) compile_cmd += " --nostdlib";
    if (no_linking) compile_cmd += " -c";
    else compile_cmd += strcmp (SYSTEM_NAME, "Darwin")
           ? " -Wl,--gc-sections" : "";
    compile_cmd += run_path_str + rpath_str;
    if (no_linking) compile_cmd += run_lib_str;
    compile_cmd += " " + intermediate_output_path;
    if (! no_linking)
      compile_cmd += input_link_file_str + run_lib_str + " -lm";
    compile_cmd += " -o " + output_path;
    if (aux) compile_cmd += " ", compile_cmd += aux;

    if (aux) std::cerr << "Going to run: " << compile_cmd << std::endl,
               fflush (stderr);  // show it immediately

    int status = system (compile_cmd.c_str ());
    if (status != 0) {
        if (debug) {
          std::cerr << compile_cmd << std::endl;
        }
        error(DALE_CC " failed");
    }

    status = remove(intermediate_output_path.c_str());
    if (status != 0) {
        if (debug) {
          std::cerr << intermediate_output_path << std::endl;
        }
        error("unable to remove temporary file");
    }

    return 0;
}
<commit_msg>dalec: `appearsToBeLib` is rewritten functionally<commit_after>#include "Generator/Generator.h"

#include "Config.h"
#include "Utils/Utils.h"
#include <cstring>
#include <cstdlib>
#include <unistd.h>
#include <sys/stat.h>
#include <getopt.h>
#include <cstdio>
#include <iostream>

/*! dalec

    The main compiler executable, responsible for organising the
    arguments for Generator, running Generator, and assembling/linking
    the results together using the system's compiler.
*/

using namespace dale;

static const char *options = "M:m:O:a:I:L:l:o:s:b:cdrR";

static bool
is_ending_on (const char *string, const char *ending)
{
  size_t sl = strlen (string), el = strlen (ending);

  return (sl >= el) && (strcmp (string + (sl - el), ending) == 0);
}

static bool
appearsToBeLib (const char *str)
{
  return is_ending_on (str, ".o") || is_ending_on (str, ".a");
}

std::string
joinWithPrefix (std::vector<const char*> strings,
                const std::string prefix, std::string buffer)
{
  for (std::vector<const char*>::iterator b = strings.begin (),
                                          e = strings.end ();
       b != e; buffer += " " + prefix + " " + (* b ++));

  return buffer;
}

int
main(int argc, char **argv)
{
    srand(time(NULL) + getpid());

    progname = argv[0];

    int opt;
    char optc;

    std::vector<const char*>
      input_files,
      input_link_files,
      compile_libs,
      run_libs,
      include_paths,
      run_paths,
      bitcode_paths,
      static_modules,
      module_paths;

    const char *output_path_arg = NULL;
    const char *module_name     = NULL;

    int produce  = ASM;
    int optlevel = 0;

    int produce_set      = 0;
    int no_linking       = 0;
    int debug            = 0;
    int no_dale_stdlib   = 0;
    int no_stdlib        = 0;
    int remove_macros    = 0;
    int no_common        = 0;
    int static_mods_all  = 0;
    int found_sm         = 0;
    int enable_cto       = 0;
    int version          = 0;
    int print_expansions = 0;

    int option_index         = 0;
    int forced_remove_macros = 0;

    static struct option long_options[] = {
        { "no-dale-stdlib",   no_argument,       &no_dale_stdlib,   1 },
        { "no-common",        no_argument,       &no_common,        1 },
        { "no-stdlib",        no_argument,       &no_stdlib,        1 },
        { "static-modules",   no_argument,       &static_mods_all,  1 },
        { "static-module",    required_argument, &found_sm,         1 },
        { "enable-cto",       no_argument,       &enable_cto,       1 },
        { "version",          no_argument,       &version,          1 },
        { "print-expansions", no_argument,       &print_expansions, 1 },
        { 0, 0, 0, 0 }
    };

    if (argc < 2) {
        error("no input files");
    }

    while ((opt = getopt_long(argc, argv, options,
                              long_options, &option_index)) != -1) {
        optc = (char) opt;

        switch (optc) {
            case 'o': {
                if (output_path_arg) {
                    error("an output path has already been specified");
                }
                output_path_arg = optarg;
                break;
            }
            case 'O': {
                optlevel = (optarg[0] - '0');
                if ((optlevel < 0) || (optlevel > 4)) {
                    error("invalid optimisation level");
                }
                break;
            }
            case 's': {
                produce_set = true;

                const char *type = optarg;
                if (!strcmp (type, "as")) produce = ASM;     else
                if (!strcmp (type, "ir")) produce = IR;      else
                if (!strcmp (type, "bc")) produce = BitCode; else
                  error ("unrecognised output file format");

                break;
            }
            case 'd': debug = 1;                                   break;
            case 'c': no_linking = 1;                              break;
            case 'r': remove_macros = 1; forced_remove_macros = 1; break;
            case 'R': remove_macros = 0; forced_remove_macros = 1; break;
            case 'I': include_paths.push_back(optarg);             break;
            case 'a': compile_libs.push_back(optarg);              break;
            case 'L': run_paths.push_back(optarg);                 break;
            case 'l': run_libs.push_back(optarg);                  break;
            case 'b': bitcode_paths.push_back(optarg);             break;
            case 'M': module_paths.push_back(optarg);              break;
            case 'm': module_name = optarg;                        break;
        };

        if (found_sm) {
            found_sm = 0;
            static_modules.push_back(optarg);
        }
    }

    if (version)
      std::cout << DALE_VERSION_MAJOR << "."
                << DALE_VERSION_MINOR << std::endl, exit (0);

    /* If the user wants an executable and has not specified either
     * way with respect to removing macros, then remove macros. */
    if (!no_linking && !produce_set && !forced_remove_macros) {
        remove_macros = 1;
    }

    /* Every argument after the options is treated as an input file.
     * Input files that end with .o or .a should go straight to the
     * linker. */
    while (optind != argc)
      {
        const char *input_file = argv [optind ++];

        (appearsToBeLib (input_file) ?
         input_link_files : input_files) .push_back (input_file);
      }
    if (input_files.size () == 0) error ("no input files");

    /* Set output_path. */
    std::string output_path;
    if (output_path_arg) output_path = output_path_arg;  // is given
    else  // otherwise construct it
      {
        output_path = input_files [0];  // leave the extension as is

        if (no_linking) output_path += ".o";
        else if (produce_set) output_path +=
                            ((produce == IR)      ? ".ll" :
                             (produce == ASM)     ? ".s"  :
                             (produce == BitCode) ? ".bc" :
                             ".unknown" );  // impossible, an error
        else output_path = "a.out";  // overwrite what was there
      }

    std::vector<std::string> so_paths;
    Generator generator;

    std::string intermediate_output_path =
      output_path + (produce_set ? "" : ".s");
    {
      FILE *output_file =
        fopen (intermediate_output_path.c_str (), "w");
      if (output_file == NULL) error ("unable to open %s for writing",
                                      intermediate_output_path.c_str (),
                                      true);
      if (! generator.run (&input_files,
                           &bitcode_paths,
                           &compile_libs,
                           &include_paths,
                           &module_paths,
                           &static_modules,
                           module_name,
                           debug,
                           produce,
                           optlevel,
                           remove_macros,
                           no_common,
                           no_dale_stdlib,
                           static_mods_all,
                           enable_cto,
                           print_expansions,
                           &so_paths,
                           output_file)) exit (1);
      if (fflush (output_file) != 0)
        error ("unable to flush the intermediate output file", true);
    }
    if (produce_set) exit (0);  // we're done

    // prepare the strings to sew the compile command with
    std::string input_file_str =
      joinWithPrefix (input_files, " ", "");
    std::string compile_lib_str =
      joinWithPrefix (compile_libs, "-l", "");
    std::string include_path_str =
      joinWithPrefix (include_paths, "-I", "");
    std::string run_path_str =
      joinWithPrefix (run_paths, "-L", "");
    std::string run_lib_str =
      joinWithPrefix (run_libs, "-l", "");
    std::string rpath_str = strcmp (SYSTEM_NAME, "Darwin") ?
      "" : joinWithPrefix (module_paths, "-rpath", "");

    std::string input_link_file_str =
      joinWithPrefix (input_link_files, " ", "");
    for (std::vector<std::string>::iterator b = so_paths.begin (),
                                            e = so_paths.end ();
         b != e; input_link_file_str += " " + (* b ++));

    // compose the compiler/linker command and execute it
    const char *aux = getenv ("DALE_CC_FLAGS");  // auxiliary options
    std::string compile_cmd = DALE_CC;
    if (no_stdlib) compile_cmd += " --nostdlib";
    if (no_linking) compile_cmd += " -c";
    else compile_cmd += strcmp (SYSTEM_NAME, "Darwin")
           ? " -Wl,--gc-sections" : "";
    compile_cmd += run_path_str + rpath_str;
    if (no_linking) compile_cmd += run_lib_str;
    compile_cmd += " " + intermediate_output_path;
    if (! no_linking)
      compile_cmd += input_link_file_str + run_lib_str + " -lm";
    compile_cmd += " -o " + output_path;
    if (aux) compile_cmd += " ", compile_cmd += aux;

    if (aux) std::cerr << "Going to run: " << compile_cmd << std::endl,
               fflush (stderr);  // show it immediately

    int status = system (compile_cmd.c_str ());
    if (status != 0) {
        if (debug) {
          std::cerr << compile_cmd << std::endl;
        }
        error(DALE_CC " failed");
    }

    status = remove(intermediate_output_path.c_str());
    if (status != 0) {
        if (debug) {
          std::cerr << intermediate_output_path << std::endl;
        }
        error("unable to remove temporary file");
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
   Copyright 2014 Software Reliability Lab, ETH Zurich

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include "nice2server.h"

#include "glog/logging.h"
#include "jsoncpp/json/json.h"
#include "jsonrpccpp/server.h"
#include "jsonrpccpp/server/connectors/httpserver.h"
#include "jsonrpccpp/common/exception.h"

#include "stringprintf.h"

#include "graph_inference.h"
#include "server_log.h"
#include "inference.h"

DEFINE_string(model, "model", "Input model files");
DEFINE_string(model_version, "", "Version of the current model");

DEFINE_string(logfile_prefix, "", "File where to log all requests and responses");

namespace {
void DropTrainingNewLine(std::string* s) {
  if (s->empty()) return;
  if ((*s)[s->size() - 1] == '\n') s->erase(s->begin() + s->size() - 1, s->end());
}
}

class Nice2ServerInternal : public jsonrpc::AbstractServer<Nice2ServerInternal> {
public:
  Nice2ServerInternal(jsonrpc::HttpServer* server) : jsonrpc::AbstractServer<Nice2ServerInternal>(*server) {
    bindAndAddMethod(
        jsonrpc::Procedure("infer", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::infer);
    bindAndAddMethod(
        jsonrpc::Procedure("nbest", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "n", jsonrpc::JSON_INTEGER,
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::nbest);

    bindAndAddMethod(
        jsonrpc::Procedure("showgraph", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::showgraph);

    inference_.LoadModel(FLAGS_model);

    if (!FLAGS_logfile_prefix.empty()) {
      logging_.reset(new Nice2ServerLog(FLAGS_logfile_prefix));
    }
  }

  void verifyVersion(const Json::Value& request){
    VLOG(3) << "Current version: " << FLAGS_model_version << ". Request version: " << request["version"];
    if (FLAGS_model_version.empty()){
      return;
    }

    if (!request.isMember("version") ||
        strcmp(request["version"].asCString(), FLAGS_model_version.c_str()) != 0){
      std::ostringstream stringStream;
      stringStream << "The version of client '" << request["version"].asString() <<
          "' does not match the server version '" << FLAGS_model_version << "'. " <<
          "Please update the client to the latest version by running 'npm update -g unuglify-js'.";
      throw jsonrpc::JsonRpcException(-31001, stringStream.str());
    }
  }

  void MaybeLogQuery(const char* method, const Json::Value& request, const Json::Value& response) {
    if (logging_.get() == NULL) {
      return;
    }

    Json::FastWriter writer;
    std::string rs1 = writer.write(request);
    std::string rs2 = writer.write(response);
    DropTrainingNewLine(&rs1);
    DropTrainingNewLine(&rs2);
    logging_->LogRecord(StringPrintf(
        "\"method\":\"%s\", "
        "\"request\":%s, "
        "\"reply\":%s",
        method, rs1.c_str(), rs2.c_str()));
  }

  void infer(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->ToJSON(&response);

    MaybeLogQuery("infer", request, response);
  }

  void nbest(const Json::Value& request, Json::Value& response)
  {
    int n = request["n"].asInt();
    int v = request["v"].asInt();

    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->GetCandidates(inference_, n, v, &response);

    MaybeLogQuery("nbest", request, response);
  }

  void showgraph(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    if (request.isMember("infer") && request["infer"].asBool() == true) {
      inference_.MapInference(query.get(), assignment.get());
    }
    inference_.DisplayGraph(query.get(), assignment.get(), &response);

    MaybeLogQuery("showgraph", request, response);
  }

private:
  GraphInference inference_;
  std::unique_ptr<Nice2ServerLog> logging_;
};

Nice2Server::Nice2Server(jsonrpc::HttpServer* server)
  : internal_(new Nice2ServerInternal(server)) {
}

Nice2Server::~Nice2Server() {
  delete internal_;
}

void Nice2Server::Listen() {
  internal_->StartListening();
  LOG(INFO) << "Nice2Server started.";
  for (;;) {
    sleep(1);
  }
  internal_->StopListening();
}
<commit_msg>fixed parameters <commit_after>/*
   Copyright 2014 Software Reliability Lab, ETH Zurich

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
 */

#include "nice2server.h"

#include "glog/logging.h"
#include "jsoncpp/json/json.h"
#include "jsonrpccpp/server.h"
#include "jsonrpccpp/server/connectors/httpserver.h"
#include "jsonrpccpp/common/exception.h"

#include "stringprintf.h"

#include "graph_inference.h"
#include "server_log.h"
#include "inference.h"

DEFINE_string(model, "model", "Input model files");
DEFINE_string(model_version, "", "Version of the current model");

DEFINE_string(logfile_prefix, "", "File where to log all requests and responses");

namespace {
void DropTrainingNewLine(std::string* s) {
  if (s->empty()) return;
  if ((*s)[s->size() - 1] == '\n') s->erase(s->begin() + s->size() - 1, s->end());
}
}

class Nice2ServerInternal : public jsonrpc::AbstractServer<Nice2ServerInternal> {
public:
  Nice2ServerInternal(jsonrpc::HttpServer* server) : jsonrpc::AbstractServer<Nice2ServerInternal>(*server) {
    bindAndAddMethod(
        jsonrpc::Procedure("infer", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::infer);
    bindAndAddMethod(
        jsonrpc::Procedure("nbest", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_ARRAY,
            // Parameters:
            "n", jsonrpc::JSON_INTEGER,
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::nbest);

    bindAndAddMethod(
        jsonrpc::Procedure("showgraph", jsonrpc::PARAMS_BY_NAME, jsonrpc::JSON_OBJECT,
            // Parameters:
            "query", jsonrpc::JSON_ARRAY,
            "assign", jsonrpc::JSON_ARRAY,
            NULL),
        &Nice2ServerInternal::showgraph);

    inference_.LoadModel(FLAGS_model);

    if (!FLAGS_logfile_prefix.empty()) {
      logging_.reset(new Nice2ServerLog(FLAGS_logfile_prefix));
    }
  }

  void verifyVersion(const Json::Value& request){
    VLOG(3) << "Current version: " << FLAGS_model_version << ". Request version: " << request["version"];
    if (FLAGS_model_version.empty()){
      return;
    }

    if (!request.isMember("version") ||
        strcmp(request["version"].asCString(), FLAGS_model_version.c_str()) != 0){
      std::ostringstream stringStream;
      stringStream << "The version of client '" << request["version"].asString() <<
          "' does not match the server version '" << FLAGS_model_version << "'. " <<
          "Please update the client to the latest version by running 'npm update -g unuglify-js'.";
      throw jsonrpc::JsonRpcException(-31001, stringStream.str());
    }
  }

  void MaybeLogQuery(const char* method, const Json::Value& request, const Json::Value& response) {
    if (logging_.get() == NULL) {
      return;
    }

    Json::FastWriter writer;
    std::string rs1 = writer.write(request);
    std::string rs2 = writer.write(response);
    DropTrainingNewLine(&rs1);
    DropTrainingNewLine(&rs2);
    logging_->LogRecord(StringPrintf(
        "\"method\":\"%s\", "
        "\"request\":%s, "
        "\"reply\":%s",
        method, rs1.c_str(), rs2.c_str()));
  }

  void infer(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->ToJSON(&response);

    MaybeLogQuery("infer", request, response);
  }

  void nbest(const Json::Value& request, Json::Value& response)
  {
    int n = request["n"].asInt();
    int v = request["v"].asInt();

    VLOG(3) << request.toStyledString();
    verifyVersion(request);
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    inference_.MapInference(query.get(), assignment.get());
    assignment->GetCandidates(inference_, v, n, &response);

    MaybeLogQuery("nbest", request, response);
  }

  void showgraph(const Json::Value& request, Json::Value& response)
  {
    VLOG(3) << request.toStyledString();
    std::unique_ptr<Nice2Query> query(inference_.CreateQuery());
    query->FromJSON(request["query"]);
    std::unique_ptr<Nice2Assignment> assignment(inference_.CreateAssignment(query.get()));
    assignment->FromJSON(request["assign"]);
    if (request.isMember("infer") && request["infer"].asBool() == true) {
      inference_.MapInference(query.get(), assignment.get());
    }
    inference_.DisplayGraph(query.get(), assignment.get(), &response);

    MaybeLogQuery("showgraph", request, response);
  }

private:
  GraphInference inference_;
  std::unique_ptr<Nice2ServerLog> logging_;
};

Nice2Server::Nice2Server(jsonrpc::HttpServer* server)
  : internal_(new Nice2ServerInternal(server)) {
}

Nice2Server::~Nice2Server() {
  delete internal_;
}

void Nice2Server::Listen() {
  internal_->StartListening();
  LOG(INFO) << "Nice2Server started.";
  for (;;) {
    sleep(1);
  }
  internal_->StopListening();
}
<|endoftext|>


<commit_before>#include "3rd_party/exception.h"
#include "3rd_party/yaml-cpp/yaml.h"
#include "common/logging.h"
#include "common/utils.h"
#include "data/vocab.h"

#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <regex>

namespace marian {

Vocab::Vocab() {}

size_t Vocab::operator[](const std::string& word) const {
  auto it = str2id_.find(word);
  if(it != str2id_.end())
    return it->second;
  else
    return UNK_ID;
}

Words Vocab::operator()(const std::vector<std::string>& lineTokens,
                        bool addEOS) const {
  Words words(lineTokens.size());
  std::transform(lineTokens.begin(),
                 lineTokens.end(),
                 words.begin(),
                 [&](const std::string& w) { return (*this)[w]; });
  if(addEOS)
    words.push_back(EOS_ID);
  return words;
}

Words Vocab::operator()(const std::string& line, bool addEOS) const {
  std::vector<std::string> lineTokens;
  Split(line, lineTokens, " ");
  return (*this)(lineTokens, addEOS);
}

std::vector<std::string> Vocab::operator()(const Words& sentence,
                                           bool ignoreEOS) const {
  std::vector<std::string> decoded;
  for(size_t i = 0; i < sentence.size(); ++i) {
    if((sentence[i] != EOS_ID || !ignoreEOS)) {
      decoded.push_back((*this)[sentence[i]]);
    }
  }
  return decoded;
}

const std::string& Vocab::operator[](size_t id) const {
  ABORT_IF(id >= id2str_.size(), "Unknown word id: ", id);
  return id2str_[id];
}

size_t Vocab::size() const {
  return id2str_.size();
}

int Vocab::loadOrCreate(const std::string& vocabPath,
                        const std::string& trainPath,
                        int max) {
  if(vocabPath.empty()) {
    if(boost::filesystem::exists(trainPath + ".json")) {
      return load(trainPath + ".json", max);
    }
    if(boost::filesystem::exists(trainPath + ".yml")) {
      return load(trainPath + ".yml", max);
    }
    create(trainPath + ".yml", trainPath);
    return load(trainPath + ".yml", max);
  } else {
    if(!boost::filesystem::exists(vocabPath))
      create(vocabPath, trainPath);
    return load(vocabPath, max);
  }
}

int Vocab::load(const std::string& vocabPath, int max) {
  bool isYaml = std::regex_search(vocabPath, std::regex(".yml$"));
  LOG(info, "[data] Loading vocabulary from {} file {}", isYaml ? "Yaml" : "text", vocabPath);
  ABORT_IF(!boost::filesystem::exists(vocabPath),
           "Vocabulary {} does not exits",
           vocabPath);

  std::map<std::string,Word> vocab;
  if (isYaml) // read from Yaml file
  {
    YAML::Node vocabNode = YAML::Load(InputFileStream(vocabPath));
    for(auto&& pair : vocabNode)
      vocab.insert({ pair.first.as<std::string>(), pair.second.as<Word>() });
  }
  else // read from flat text file
  {
    std::ifstream in(vocabPath);
    std::string line;
    while (std::getline(in, line))
      vocab.insert({ line, vocab.size() });
    ABORT_IF(in.bad(), "Vocabulary file {} could not be read", vocabPath);
  }

  std::unordered_set<Word> seenSpecial;

  for(auto&& pair : vocab) {
    auto str = pair.first;
    auto id = pair.second;

    if(SPEC2SYM.count(str)) {
      seenSpecial.insert(id);
    }

    if(!max || id < (Word)max) { // note: this requires ids to be sorted by frequency
      str2id_[str] = id;
      if(id >= id2str_.size())
        id2str_.resize(id + 1);
      id2str_[id] = str;
    }
  }
  ABORT_IF(id2str_.empty(), "Empty vocabulary: ", vocabPath);

  // </s> and <unk> are expected at specific positions
  auto requireWord = [&](Word id, const std::string& str)
  {
    auto iter = str2id_.find(str);
    if (iter != str2id_.end()) // word already in vocab: must be at right index, else fail
    {
      ABORT_IF(iter->second != id, "vocabulary entry '{}' is expected to have id {}", str, id);
#if 0
      return;
#else
      // some old config needs this patching for now
      // BUGBUG: If another word already uses this id, then str2id_ for that will still exist.
#endif
    }
    str2id_[str] = id;
    id2str_[id] = str;
  };
  requireWord(EOS_ID, EOS_STR);
  requireWord(UNK_ID, UNK_STR);
  for(auto id : seenSpecial)
    requireWord(id, SYM2SPEC.at(id));

  return std::max((int)id2str_.size(), max);
}

class Vocab::VocabFreqOrderer {
private:
  std::unordered_map<std::string, size_t>& counter_;

public:
  VocabFreqOrderer(std::unordered_map<std::string, size_t>& counter)
      : counter_(counter) {}

  bool operator()(const std::string& a, const std::string& b) const {
    return counter_[a] > counter_[b] || (counter_[a] == counter_[b] && a < b);
  }
};

void Vocab::create(const std::string& vocabPath, const std::string& trainPath) {
  LOG(info, "[data] Creating vocabulary {} from {}", vocabPath, trainPath);

  boost::filesystem::path path(vocabPath);
  auto dir = path.parent_path();
  if(dir.empty())
    dir = boost::filesystem::current_path();

  ABORT_IF(!dir.empty() && !boost::filesystem::is_directory(dir),
           "Specified vocab directory {} does not exist",
           dir);

  ABORT_IF(!dir.empty()
               && !(boost::filesystem::status(dir).permissions()
                    & boost::filesystem::owner_write),
           "No write permission in vocab directory {}",
           dir);

  ABORT_IF(boost::filesystem::exists(vocabPath),
           "Vocab file '{}' exists. Not overwriting",
           vocabPath);

  InputFileStream trainStrm(trainPath);
  OutputFileStream vocabStrm(vocabPath);
  create(trainStrm, vocabStrm);
}

void Vocab::create(InputFileStream& trainStrm,
                   OutputFileStream& vocabStrm,
                   size_t maxSize) {
  std::string line;
  std::unordered_map<std::string, size_t> counter;

  std::unordered_set<Word> seenSpecial;

  while(getline((std::istream&)trainStrm, line)) {
    std::vector<std::string> toks;
    Split(line, toks);

    for(const std::string& tok : toks) {
      if(SPEC2SYM.count(tok)) {
        seenSpecial.insert(SPEC2SYM.at(tok));
        continue;
      }

      auto iter = counter.find(tok);
      if(iter == counter.end())
        counter[tok] = 1;
      else
        iter->second++;
    }
  }

  std::vector<std::string> vocabVec;
  for(auto& p : counter)
    vocabVec.push_back(p.first);

  std::sort(vocabVec.begin(), vocabVec.end(), VocabFreqOrderer(counter));

  YAML::Node vocabYaml;
  vocabYaml.force_insert(EOS_STR, EOS_ID);
  vocabYaml.force_insert(UNK_STR, UNK_ID);

  for(auto word : seenSpecial)
    vocabYaml.force_insert(SYM2SPEC.at(word), word);

  Word maxSpec = 1;
  for(auto i : seenSpecial)
    if(i > maxSpec)
      maxSpec = i;

  auto vocabSize = vocabVec.size();
  if(maxSize > maxSpec)
    vocabSize = std::min(maxSize - maxSpec - 1, vocabVec.size());

  for(size_t i = 0; i < vocabSize; ++i)
    vocabYaml.force_insert(vocabVec[i], i + maxSpec + 1);

  (std::ostream&)vocabStrm << vocabYaml;
}
}
<commit_msg>added a BUGBUG comment<commit_after>#include "3rd_party/exception.h"
#include "3rd_party/yaml-cpp/yaml.h"
#include "common/logging.h"
#include "common/utils.h"
#include "data/vocab.h"

#include <algorithm>
#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <regex>

namespace marian {

Vocab::Vocab() {}

size_t Vocab::operator[](const std::string& word) const {
  auto it = str2id_.find(word);
  if(it != str2id_.end())
    return it->second;
  else
    return UNK_ID;
}

Words Vocab::operator()(const std::vector<std::string>& lineTokens,
                        bool addEOS) const {
  Words words(lineTokens.size());
  std::transform(lineTokens.begin(),
                 lineTokens.end(),
                 words.begin(),
                 [&](const std::string& w) { return (*this)[w]; });
  if(addEOS)
    words.push_back(EOS_ID);
  return words;
}

Words Vocab::operator()(const std::string& line, bool addEOS) const {
  std::vector<std::string> lineTokens;
  Split(line, lineTokens, " ");
  return (*this)(lineTokens, addEOS);
}

std::vector<std::string> Vocab::operator()(const Words& sentence,
                                           bool ignoreEOS) const {
  std::vector<std::string> decoded;
  for(size_t i = 0; i < sentence.size(); ++i) {
    if((sentence[i] != EOS_ID || !ignoreEOS)) {
      decoded.push_back((*this)[sentence[i]]);
    }
  }
  return decoded;
}

const std::string& Vocab::operator[](size_t id) const {
  ABORT_IF(id >= id2str_.size(), "Unknown word id: ", id);
  return id2str_[id];
}

size_t Vocab::size() const {
  return id2str_.size();
}

int Vocab::loadOrCreate(const std::string& vocabPath,
                        const std::string& trainPath,
                        int max) {
  if(vocabPath.empty()) {
    if(boost::filesystem::exists(trainPath + ".json")) {
      return load(trainPath + ".json", max);
    }
    if(boost::filesystem::exists(trainPath + ".yml")) {
      return load(trainPath + ".yml", max);
    }
    create(trainPath + ".yml", trainPath);
    return load(trainPath + ".yml", max);
  } else {
    if(!boost::filesystem::exists(vocabPath))
      create(vocabPath, trainPath);
    return load(vocabPath, max);
  }
}

int Vocab::load(const std::string& vocabPath, int max) {
  bool isYaml = std::regex_search(vocabPath, std::regex(".yml$")); // BUGBUG: Is .json also indicative of a Yaml file? Whats "\.{yml,json}$" in C++ regex?
  LOG(info, "[data] Loading vocabulary from {} file {}", isYaml ? "Yaml" : "text", vocabPath);
  ABORT_IF(!boost::filesystem::exists(vocabPath),
           "Vocabulary {} does not exits",
           vocabPath);

  std::map<std::string,Word> vocab;
  if (isYaml) // read from Yaml file
  {
    YAML::Node vocabNode = YAML::Load(InputFileStream(vocabPath));
    for(auto&& pair : vocabNode)
      vocab.insert({ pair.first.as<std::string>(), pair.second.as<Word>() });
  }
  else // read from flat text file
  {
    std::ifstream in(vocabPath);
    std::string line;
    while (std::getline(in, line))
      vocab.insert({ line, vocab.size() });
    ABORT_IF(in.bad(), "Vocabulary file {} could not be read", vocabPath);
  }

  std::unordered_set<Word> seenSpecial;

  for(auto&& pair : vocab) {
    auto str = pair.first;
    auto id = pair.second;

    if(SPEC2SYM.count(str)) {
      seenSpecial.insert(id);
    }

    if(!max || id < (Word)max) { // note: this requires ids to be sorted by frequency
      str2id_[str] = id;
      if(id >= id2str_.size())
        id2str_.resize(id + 1);
      id2str_[id] = str;
    }
  }
  ABORT_IF(id2str_.empty(), "Empty vocabulary: ", vocabPath);

  // </s> and <unk> are expected at specific positions
  auto requireWord = [&](Word id, const std::string& str)
  {
    auto iter = str2id_.find(str);
    if (iter != str2id_.end()) // word already in vocab: must be at right index, else fail
    {
      ABORT_IF(iter->second != id, "vocabulary entry '{}' is expected to have id {}", str, id);
#if 0
      return;
#else
      // some old config needs this patching for now
      // BUGBUG: If another word already uses this id, then str2id_ for that will still exist.
#endif
    }
    str2id_[str] = id;
    id2str_[id] = str;
  };
  requireWord(EOS_ID, EOS_STR);
  requireWord(UNK_ID, UNK_STR);
  for(auto id : seenSpecial)
    requireWord(id, SYM2SPEC.at(id));

  return std::max((int)id2str_.size(), max);
}

class Vocab::VocabFreqOrderer {
private:
  std::unordered_map<std::string, size_t>& counter_;

public:
  VocabFreqOrderer(std::unordered_map<std::string, size_t>& counter)
      : counter_(counter) {}

  bool operator()(const std::string& a, const std::string& b) const {
    return counter_[a] > counter_[b] || (counter_[a] == counter_[b] && a < b);
  }
};

void Vocab::create(const std::string& vocabPath, const std::string& trainPath) {
  LOG(info, "[data] Creating vocabulary {} from {}", vocabPath, trainPath);

  boost::filesystem::path path(vocabPath);
  auto dir = path.parent_path();
  if(dir.empty())
    dir = boost::filesystem::current_path();

  ABORT_IF(!dir.empty() && !boost::filesystem::is_directory(dir),
           "Specified vocab directory {} does not exist",
           dir);

  ABORT_IF(!dir.empty()
               && !(boost::filesystem::status(dir).permissions()
                    & boost::filesystem::owner_write),
           "No write permission in vocab directory {}",
           dir);

  ABORT_IF(boost::filesystem::exists(vocabPath),
           "Vocab file '{}' exists. Not overwriting",
           vocabPath);

  InputFileStream trainStrm(trainPath);
  OutputFileStream vocabStrm(vocabPath);
  create(trainStrm, vocabStrm);
}

void Vocab::create(InputFileStream& trainStrm,
                   OutputFileStream& vocabStrm,
                   size_t maxSize) {
  std::string line;
  std::unordered_map<std::string, size_t> counter;

  std::unordered_set<Word> seenSpecial;

  while(getline((std::istream&)trainStrm, line)) {
    std::vector<std::string> toks;
    Split(line, toks);

    for(const std::string& tok : toks) {
      if(SPEC2SYM.count(tok)) {
        seenSpecial.insert(SPEC2SYM.at(tok));
        continue;
      }

      auto iter = counter.find(tok);
      if(iter == counter.end())
        counter[tok] = 1;
      else
        iter->second++;
    }
  }

  std::vector<std::string> vocabVec;
  for(auto& p : counter)
    vocabVec.push_back(p.first);

  std::sort(vocabVec.begin(), vocabVec.end(), VocabFreqOrderer(counter));

  YAML::Node vocabYaml;
  vocabYaml.force_insert(EOS_STR, EOS_ID);
  vocabYaml.force_insert(UNK_STR, UNK_ID);

  for(auto word : seenSpecial)
    vocabYaml.force_insert(SYM2SPEC.at(word), word);

  Word maxSpec = 1;
  for(auto i : seenSpecial)
    if(i > maxSpec)
      maxSpec = i;

  auto vocabSize = vocabVec.size();
  if(maxSize > maxSpec)
    vocabSize = std::min(maxSize - maxSpec - 1, vocabVec.size());

  for(size_t i = 0; i < vocabSize; ++i)
    vocabYaml.force_insert(vocabVec[i], i + maxSpec + 1);

  (std::ostream&)vocabStrm << vocabYaml;
}
}
<|endoftext|>


<commit_before>/*
 * Copyright 2017 deepstreamHub GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdint>

#include <algorithm>
#include <chrono>
#include <stdexcept>

#include <buffer.hpp>
#include <client.hpp>
#include <deepstream.hpp>
#include <error_handler.hpp>
#include <message.hpp>
#include <message_builder.hpp>
#include <scope_guard.hpp>
#include <websockets.hpp>
#include <websockets/poco.hpp>
#include <use.hpp>

#include <cassert>

namespace deepstream
{

Client Client::make(
	std::unique_ptr<websockets::Client> p_websocket,
	std::unique_ptr<ErrorHandler> p_error_handler)
{
	assert( p_websocket );
	assert( p_error_handler );

	const unsigned MAX_NUM_REDIRECTIONS = 3;

	for(unsigned num_redirections = 0;
		num_redirections < MAX_NUM_REDIRECTIONS;
		++num_redirections)
	{
		p_websocket->set_receive_timeout( std::chrono::seconds(1) );

		const std::string uri = p_websocket->uri();

		Client c(
			std::move(p_websocket),
			std::move(p_error_handler)
		);

		Buffer buffer;
		parser::MessageList messages;
		client::State& state = c.state_;

		if( c.receive_(&buffer, &messages) != websockets::State::OPEN )
			return c;

		if( messages.size() != 1 || state != client::State::CHALLENGING )
		{
			c.close();
			return c;
		}

		{
			MessageBuilder chr(Topic::CONNECTION, Action::CHALLENGE_RESPONSE);
			chr.add_argument(uri);

			if( c.send_(chr) != websockets::State::OPEN )
				return c;
		}

		if( c.receive_(&buffer, &messages) != websockets::State::OPEN )
			return c;

		if( messages.size() != 1 )
		{
			c.close();
			return c;
		}

		if( state == client::State::AWAIT_AUTHENTICATION )
			return c;

		if( state == client::State::AWAIT_CONNECTION )
		{
			const Message& redirect_msg = messages.front();
			assert( redirect_msg.num_arguments() == 1 );

			const Buffer& uri_buffer = redirect_msg[0];
			std::string new_uri( uri_buffer.cbegin(), uri_buffer.cend() );

			p_websocket = c.p_websocket_->construct(new_uri);
			p_error_handler = std::move(c.p_error_handler_);

			continue;
		}

		c.close();
		return c;
	}

	assert( p_error_handler );
	p_error_handler->too_many_redirections(MAX_NUM_REDIRECTIONS);

	return Client( nullptr, std::move(p_error_handler) );
}

Client Client::make(const std::string& uri)
{
	return Client::make(
		std::unique_ptr<websockets::Client>(new websockets::poco::Client(uri)),
		std::unique_ptr<ErrorHandler>(new ErrorHandler())
	);
}

Client::Client(
	std::unique_ptr<websockets::Client> p_websocket,
	std::unique_ptr<ErrorHandler> p_error_handler
) :
	event(
		[this] (const Message& message) -> bool {
			return send_(message) == websockets::State::OPEN;
		}
	),
	presence(
		[this] (const Message& message) -> bool {
			return send_(message) == websockets::State::OPEN;
		}
	),
	state_(
		p_websocket
		? client::State::AWAIT_CONNECTION
		: client::State::ERROR
	),
	p_websocket_( std::move(p_websocket) ),
	p_error_handler_( std::move(p_error_handler) )
{
	assert( p_error_handler_ );
}

client::State Client::login(
	const std::string& auth, Buffer* p_user_data)
{
	if( !p_websocket_ )
		return client::State::ERROR;

	if( state_ != client::State::AWAIT_AUTHENTICATION )
		throw std::logic_error("Cannot login() in current state");

	MessageBuilder areq(Topic::AUTH, Action::REQUEST);
	areq.add_argument(auth);

	if( send_(areq) != websockets::State::OPEN )
		return state_;

	Buffer buffer;
	parser::MessageList messages;

	if( receive_(&buffer, &messages) != websockets::State::OPEN )
		return state_;

	if( messages.size() != 1 )
	{
		close();
		return client::State::ERROR;
	}

	const Message& msg = messages.front();

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::REQUEST &&
		msg.is_ack() )
	{
		assert( state_ == client::State::CONNECTED );

		if( msg.num_arguments() == 0 && p_user_data )
			p_user_data->clear();
		else if( msg.num_arguments() == 1 && p_user_data )
			*p_user_data = msg[0];

		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_INVALID_AUTH_DATA )
	{
		assert( state_ == client::State::AWAIT_AUTHENTICATION );

		p_error_handler_->authentication_error(msg);
		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_INVALID_AUTH_MSG )
	{
		p_error_handler_->authentication_error(msg);
		close();
		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_TOO_MANY_AUTH_ATTEMPTS )
	{
		p_error_handler_->authentication_error(msg);
		close();
		return state_;
	}

	close();
	return client::State::ERROR;
}

void Client::close()
{
	assert( p_websocket_ || state_ == client::State::ERROR );

	if( !p_websocket_ )
		return;

	state_ = client::State::DISCONNECTED;

		p_websocket_->close();
}

void Client::process_messages()
{
	if( !p_websocket_ )
		return;

	Buffer buffer;
	parser::MessageList messages;

	p_websocket_->set_receive_timeout( std::chrono::milliseconds(1) );

	while( receive_(&buffer, &messages) == websockets::State::OPEN )
	{
		if( messages.empty() )
			break;

		for(const Message& message : messages)
		{
			if( message.topic() == Topic::CONNECTION &&
				message.action() == Action::PING )
			{
				MessageBuilder pong( Topic::CONNECTION, Action::PONG );
				send_(pong);
				continue;
			}

			switch( message.topic() )
			{
				case Topic::EVENT:
					event.notify_(message);
					break;

				case Topic::PRESENCE:
					presence.notify_(message);
					break;

				default:
					assert(0);
					close();
					return;
			}
		}
	}
}

websockets::State Client::receive_(
	Buffer* p_buffer, parser::MessageList* p_messages)
{
	assert( p_buffer );
	assert( p_messages );

	if( !p_websocket_ )
		return websockets::State::ERROR;

	auto receive_ret = p_websocket_->receive_frame();
	websockets::State ws_state = receive_ret.first;
	std::unique_ptr<websockets::Frame> p_frame = std::move(receive_ret.second);

	if( ws_state == websockets::State::OPEN && !p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		return ws_state;
	}

	if( ws_state == websockets::State::CLOSED && p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		close();

		return ws_state;
	}

	if( ws_state == websockets::State::CLOSED && !p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		close();
		p_error_handler_->sudden_disconnect( p_websocket_->uri() );

		return ws_state;
	}

	if( ws_state == websockets::State::ERROR )
	{
		assert( p_frame );

		close();
		p_error_handler_->invalid_close_frame_size(*p_frame);

		return ws_state;
	}

	assert( ws_state == websockets::State::OPEN );
	assert( p_frame );

	if( p_frame->flags() !=
		(websockets::Frame::Bit::FIN | websockets::Frame::Opcode::TEXT_FRAME) )
	{
		p_error_handler_->unexpected_websocket_frame_flags( p_frame->flags() );
		close();

		return websockets::State::ERROR;
	}

	const Buffer& payload = p_frame->payload();
	p_buffer->assign( payload.cbegin(), payload.cend() );
	p_buffer->push_back(0);
	p_buffer->push_back(0);

	auto parser_ret = parser::execute( p_buffer->data(), p_buffer->size() );
	const parser::ErrorList& errors = parser_ret.second;

	std::for_each(
		errors.cbegin(), errors.cend(),
		[this] (const parser::Error& e) {
			this->p_error_handler_->parser_error(e);
		}
	);

	if( !errors.empty() )
	{
		p_buffer->clear();
		p_messages->clear();

		close();
		return websockets::State::ERROR;
	}

	*p_messages = std::move(parser_ret.first);

	for(auto it = p_messages->cbegin(); it != p_messages->cend(); ++it)
	{
		const Message& msg = *it;

		client::State old_state = state_;
		client::State new_state =
			client::transition(old_state, msg, Sender::SERVER);

		if( new_state == client::State::ERROR )
		{
			close();
			p_error_handler_->invalid_state_transition(old_state, msg);

			return websockets::State::ERROR;
		}

		if( new_state == client::State::DISCONNECTED )
			return websockets::State::OPEN;

		state_ = new_state;
	}

	return ws_state;
}

websockets::State Client::send_(const Message& message)
{
	if( !p_websocket_ )
		return websockets::State::ERROR;

	client::State new_state =
		client::transition(state_, message, Sender::CLIENT);
	assert( new_state != client::State::ERROR );

	if( new_state == client::State::ERROR )
		throw std::logic_error( "Invalid client state transition" );

	state_ = new_state;

	return send_frame_( message.to_binary() );
}

websockets::State Client::send_frame_(const Buffer& buffer)
{
	return send_frame_(
		buffer,
		websockets::Frame::Bit::FIN | websockets::Frame::Opcode::TEXT_FRAME
	);
}

websockets::State Client::send_frame_(
	const Buffer& buffer,
	websockets::Frame::Flags flags)
{
	if( !p_websocket_ )
		return websockets::State::ERROR;

	try
	{
		websockets::State state = p_websocket_->send_frame(buffer, flags);

		if( state != websockets::State::OPEN )
		{
			close();
			p_error_handler_->sudden_disconnect( p_websocket_->uri() );

			return websockets::State::CLOSED;
		}

		return state;
	}
	catch(std::system_error& e)
	{
		p_error_handler_->system_error(e);
	}
	catch(std::exception& e)
	{
		p_error_handler_->websocket_exception(e);
	}

	close();
	return websockets::State::ERROR;
}

}
<commit_msg>Client: fix return value<commit_after>/*
 * Copyright 2017 deepstreamHub GmbH
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include <cstdint>

#include <algorithm>
#include <chrono>
#include <stdexcept>

#include <buffer.hpp>
#include <client.hpp>
#include <deepstream.hpp>
#include <error_handler.hpp>
#include <message.hpp>
#include <message_builder.hpp>
#include <scope_guard.hpp>
#include <websockets.hpp>
#include <websockets/poco.hpp>
#include <use.hpp>

#include <cassert>

namespace deepstream
{

Client Client::make(
	std::unique_ptr<websockets::Client> p_websocket,
	std::unique_ptr<ErrorHandler> p_error_handler)
{
	assert( p_websocket );
	assert( p_error_handler );

	const unsigned MAX_NUM_REDIRECTIONS = 3;

	for(unsigned num_redirections = 0;
		num_redirections < MAX_NUM_REDIRECTIONS;
		++num_redirections)
	{
		p_websocket->set_receive_timeout( std::chrono::seconds(1) );

		const std::string uri = p_websocket->uri();

		Client c(
			std::move(p_websocket),
			std::move(p_error_handler)
		);

		Buffer buffer;
		parser::MessageList messages;
		client::State& state = c.state_;

		if( c.receive_(&buffer, &messages) != websockets::State::OPEN )
			return c;

		if( messages.size() != 1 || state != client::State::CHALLENGING )
		{
			c.close();
			return c;
		}

		{
			MessageBuilder chr(Topic::CONNECTION, Action::CHALLENGE_RESPONSE);
			chr.add_argument(uri);

			if( c.send_(chr) != websockets::State::OPEN )
				return c;
		}

		if( c.receive_(&buffer, &messages) != websockets::State::OPEN )
			return c;

		if( messages.size() != 1 )
		{
			c.close();
			return c;
		}

		if( state == client::State::AWAIT_AUTHENTICATION )
			return c;

		if( state == client::State::AWAIT_CONNECTION )
		{
			const Message& redirect_msg = messages.front();
			assert( redirect_msg.num_arguments() == 1 );

			const Buffer& uri_buffer = redirect_msg[0];
			std::string new_uri( uri_buffer.cbegin(), uri_buffer.cend() );

			p_websocket = c.p_websocket_->construct(new_uri);
			p_error_handler = std::move(c.p_error_handler_);

			continue;
		}

		c.close();
		return c;
	}

	assert( p_error_handler );
	p_error_handler->too_many_redirections(MAX_NUM_REDIRECTIONS);

	return Client( nullptr, std::move(p_error_handler) );
}

Client Client::make(const std::string& uri)
{
	return Client::make(
		std::unique_ptr<websockets::Client>(new websockets::poco::Client(uri)),
		std::unique_ptr<ErrorHandler>(new ErrorHandler())
	);
}

Client::Client(
	std::unique_ptr<websockets::Client> p_websocket,
	std::unique_ptr<ErrorHandler> p_error_handler
) :
	event(
		[this] (const Message& message) -> bool {
			return send_(message) == websockets::State::OPEN;
		}
	),
	presence(
		[this] (const Message& message) -> bool {
			return send_(message) == websockets::State::OPEN;
		}
	),
	state_(
		p_websocket
		? client::State::AWAIT_CONNECTION
		: client::State::ERROR
	),
	p_websocket_( std::move(p_websocket) ),
	p_error_handler_( std::move(p_error_handler) )
{
	assert( p_error_handler_ );
}

client::State Client::login(
	const std::string& auth, Buffer* p_user_data)
{
	if( !p_websocket_ )
		return client::State::ERROR;

	if( state_ != client::State::AWAIT_AUTHENTICATION )
		throw std::logic_error("Cannot login() in current state");

	MessageBuilder areq(Topic::AUTH, Action::REQUEST);
	areq.add_argument(auth);

	if( send_(areq) != websockets::State::OPEN )
		return state_;

	Buffer buffer;
	parser::MessageList messages;

	if( receive_(&buffer, &messages) != websockets::State::OPEN )
		return state_;

	if( messages.size() != 1 )
	{
		close();
		return state_;
	}

	const Message& msg = messages.front();

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::REQUEST &&
		msg.is_ack() )
	{
		assert( state_ == client::State::CONNECTED );

		if( msg.num_arguments() == 0 && p_user_data )
			p_user_data->clear();
		else if( msg.num_arguments() == 1 && p_user_data )
			*p_user_data = msg[0];

		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_INVALID_AUTH_DATA )
	{
		assert( state_ == client::State::AWAIT_AUTHENTICATION );

		p_error_handler_->authentication_error(msg);
		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_INVALID_AUTH_MSG )
	{
		p_error_handler_->authentication_error(msg);
		close();
		return state_;
	}

	if( msg.topic() == Topic::AUTH &&
		msg.action() == Action::ERROR_TOO_MANY_AUTH_ATTEMPTS )
	{
		p_error_handler_->authentication_error(msg);
		close();
		return state_;
	}

	close();
	return client::State::ERROR;
}

void Client::close()
{
	assert( p_websocket_ || state_ == client::State::ERROR );

	if( !p_websocket_ )
		return;

	state_ = client::State::DISCONNECTED;

		p_websocket_->close();
}

void Client::process_messages()
{
	if( !p_websocket_ )
		return;

	Buffer buffer;
	parser::MessageList messages;

	p_websocket_->set_receive_timeout( std::chrono::milliseconds(1) );

	while( receive_(&buffer, &messages) == websockets::State::OPEN )
	{
		if( messages.empty() )
			break;

		for(const Message& message : messages)
		{
			if( message.topic() == Topic::CONNECTION &&
				message.action() == Action::PING )
			{
				MessageBuilder pong( Topic::CONNECTION, Action::PONG );
				send_(pong);
				continue;
			}

			switch( message.topic() )
			{
				case Topic::EVENT:
					event.notify_(message);
					break;

				case Topic::PRESENCE:
					presence.notify_(message);
					break;

				default:
					assert(0);
					close();
					return;
			}
		}
	}
}

websockets::State Client::receive_(
	Buffer* p_buffer, parser::MessageList* p_messages)
{
	assert( p_buffer );
	assert( p_messages );

	if( !p_websocket_ )
		return websockets::State::ERROR;

	auto receive_ret = p_websocket_->receive_frame();
	websockets::State ws_state = receive_ret.first;
	std::unique_ptr<websockets::Frame> p_frame = std::move(receive_ret.second);

	if( ws_state == websockets::State::OPEN && !p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		return ws_state;
	}

	if( ws_state == websockets::State::CLOSED && p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		close();

		return ws_state;
	}

	if( ws_state == websockets::State::CLOSED && !p_frame )
	{
		p_buffer->clear();
		p_messages->clear();

		close();
		p_error_handler_->sudden_disconnect( p_websocket_->uri() );

		return ws_state;
	}

	if( ws_state == websockets::State::ERROR )
	{
		assert( p_frame );

		close();
		p_error_handler_->invalid_close_frame_size(*p_frame);

		return ws_state;
	}

	assert( ws_state == websockets::State::OPEN );
	assert( p_frame );

	if( p_frame->flags() !=
		(websockets::Frame::Bit::FIN | websockets::Frame::Opcode::TEXT_FRAME) )
	{
		p_error_handler_->unexpected_websocket_frame_flags( p_frame->flags() );
		close();

		return websockets::State::ERROR;
	}

	const Buffer& payload = p_frame->payload();
	p_buffer->assign( payload.cbegin(), payload.cend() );
	p_buffer->push_back(0);
	p_buffer->push_back(0);

	auto parser_ret = parser::execute( p_buffer->data(), p_buffer->size() );
	const parser::ErrorList& errors = parser_ret.second;

	std::for_each(
		errors.cbegin(), errors.cend(),
		[this] (const parser::Error& e) {
			this->p_error_handler_->parser_error(e);
		}
	);

	if( !errors.empty() )
	{
		p_buffer->clear();
		p_messages->clear();

		close();
		return websockets::State::ERROR;
	}

	*p_messages = std::move(parser_ret.first);

	for(auto it = p_messages->cbegin(); it != p_messages->cend(); ++it)
	{
		const Message& msg = *it;

		client::State old_state = state_;
		client::State new_state =
			client::transition(old_state, msg, Sender::SERVER);

		if( new_state == client::State::ERROR )
		{
			close();
			p_error_handler_->invalid_state_transition(old_state, msg);

			return websockets::State::ERROR;
		}

		if( new_state == client::State::DISCONNECTED )
			return websockets::State::OPEN;

		state_ = new_state;
	}

	return ws_state;
}

websockets::State Client::send_(const Message& message)
{
	if( !p_websocket_ )
		return websockets::State::ERROR;

	client::State new_state =
		client::transition(state_, message, Sender::CLIENT);
	assert( new_state != client::State::ERROR );

	if( new_state == client::State::ERROR )
		throw std::logic_error( "Invalid client state transition" );

	state_ = new_state;

	return send_frame_( message.to_binary() );
}

websockets::State Client::send_frame_(const Buffer& buffer)
{
	return send_frame_(
		buffer,
		websockets::Frame::Bit::FIN | websockets::Frame::Opcode::TEXT_FRAME
	);
}

websockets::State Client::send_frame_(
	const Buffer& buffer,
	websockets::Frame::Flags flags)
{
	if( !p_websocket_ )
		return websockets::State::ERROR;

	try
	{
		websockets::State state = p_websocket_->send_frame(buffer, flags);

		if( state != websockets::State::OPEN )
		{
			close();
			p_error_handler_->sudden_disconnect( p_websocket_->uri() );

			return websockets::State::CLOSED;
		}

		return state;
	}
	catch(std::system_error& e)
	{
		p_error_handler_->system_error(e);
	}
	catch(std::exception& e)
	{
		p_error_handler_->websocket_exception(e);
	}

	close();
	return websockets::State::ERROR;
}

}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>

using std::vector;
using std::cout;
using std::endl;
using std::cin;

int main()
{
    vector<int> ivec;
    for (int i; cin >> i; ivec.push_back(i));

    if (ivec.empty())
    {
        cout << "input at least one integer." << endl;
        return -1;
    }

    auto size = ivec.size();
    if (size % 2 != 0) size = size / 2 + 1;
    else size /= 2;

    for (int i = 0; i != size; ++i)
        cout << ivec[i] + ivec[ivec.size() - i - 1] << " ";
    cout << endl;

    return 0;
}
<commit_msg>Revise redundant version size<commit_after>#include <iostream>
#include <vector>

using std::vector;
using std::cout;
using std::endl;
using std::cin;

int main()
{
    vector<int> ivec;
    for (int i; cin >> i; ivec.push_back(i));

    if (ivec.empty())
    {
        cout << "input at least one integer." << endl;
        return -1;
    }

    // If the vector has odd size, element in the middle will add to itself.
    auto size = (ivec.size() + 1) / 2;

    for (int i = 0; i != size; ++i)
        cout << ivec[i] + ivec[ivec.size() - i - 1] << " ";
    cout << endl;

    return 0;
}
<|endoftext|>


<commit_before>#include "widgets/ui_scroll_pane.h"
#include "ui_style.h"
#include "halley/support/logger.h"

using namespace Halley;

UIScrollPane::UIScrollPane(String id, Vector2f clipSize, UISizer&& sizer, bool scrollHorizontal, bool scrollVertical)
	: UIWidget(std::move(id), Vector2f(), std::move(sizer))
	, clipSize(clipSize)
	, scrollSpeed(50.0f)
	, scrollHorizontal(scrollHorizontal)
	, scrollVertical(scrollVertical)
{
	setHandle(UIEventType::MouseWheel, [this] (const UIEvent& event)
	{
		onMouseWheel(event);
	});

	setHandle(UIEventType::MakeAreaVisible, [this] (const UIEvent& event)
	{
		scrollToShow(event.getRectData() + getBasePosition(event.getSourceId()), false);
	});

	setHandle(UIEventType::MakeAreaVisibleCentered, [this] (const UIEvent& event)
	{
		scrollToShow(event.getRectData() + getBasePosition(event.getSourceId()), true);
	});
}

UIScrollPane::UIScrollPane(Vector2f clipSize, UISizer&& sizer, bool scrollHorizontal, bool scrollVertical)
: UIScrollPane("", clipSize, std::move(sizer), scrollHorizontal, scrollVertical) {

}

Vector2f UIScrollPane::getScrollPosition() const
{
	return scrollPos;
}

Vector2f UIScrollPane::getRelativeScrollPosition() const
{
	return scrollPos / std::max(contentsSize, Vector2f(1.0f, 1.0f));
}

Vector2f UIScrollPane::getRelativeScrollEndPosition() const
{
	return (scrollPos + clipSize) / std::max(contentsSize, Vector2f(1.0f, 1.0f));
}

void UIScrollPane::scrollTo(Vector2f position)
{
	if (scrollHorizontal) {
		scrollPos.x = clamp2(position.x, 0.0f, contentsSize.x - getSize().x);
	}

	if (scrollVertical) {
		scrollPos.y = clamp2(position.y, 0.0f, contentsSize.y - getSize().y);
	}
}

void UIScrollPane::scrollBy(Vector2f delta)
{
	scrollTo(scrollPos + delta);
}

void UIScrollPane::setScrollSpeed(float speed)
{
	scrollSpeed = speed;
}

void UIScrollPane::update(Time t, bool moved)
{
	refresh();
}

bool UIScrollPane::canScroll(UIScrollDirection direction) const
{
	auto contentsSize = UIWidget::getLayoutMinimumSize(false);
	if (direction == UIScrollDirection::Horizontal) {
		return scrollHorizontal && getSize().x < contentsSize.x;
	} else {
		return scrollVertical && getSize().y < contentsSize.y;
	}
}

float UIScrollPane::getCoverageSize(UIScrollDirection direction) const
{
	auto contentsSize = UIWidget::getLayoutMinimumSize(false);
	if (direction == UIScrollDirection::Horizontal) {
		return getSize().x / contentsSize.x;
	} else {
		return getSize().y / contentsSize.y;
	}
}

void UIScrollPane::setScrollWheelEnabled(bool enabled)
{
	scrollWheelEnabled = enabled;
}

bool UIScrollPane::isScrollWheelEnabled() const
{
	return scrollWheelEnabled;
}

void UIScrollPane::refresh(bool force)
{
	if (!scrollHorizontal) {
		clipSize.x = getSize().x;
		scrollPos.x = 0;
	}
	if (!scrollVertical) {
		clipSize.y = getSize().y;
		scrollPos.y = 0;
	}
	contentsSize = UIWidget::getLayoutMinimumSize(false);

	setMouseClip(getRect(), force);
	scrollTo(getScrollPosition());
}

void UIScrollPane::drawChildren(UIPainter& painter) const
{
	auto p = painter.withClip(getRect());
	UIWidget::drawChildren(p);
}

Vector2f UIScrollPane::getLayoutMinimumSize(bool force) const
{
	auto size = UIWidget::getLayoutMinimumSize(false);
	if (scrollHorizontal) {
		size.x = std::min(size.x, clipSize.x);
	}
	if (scrollVertical) {
		size.y = std::min(size.y, clipSize.y);
	}
	return size;
}

bool UIScrollPane::canInteractWithMouse() const
{
	return true;
}

void UIScrollPane::onLayout()
{
	refresh();
}

void UIScrollPane::onMouseWheel(const UIEvent& event)
{
	if (scrollWheelEnabled) {
		const float delta = scrollSpeed * float(event.getIntData());
		if (scrollVertical) {
			scrollBy(Vector2f(0.0f, -delta));
		} else {
			scrollBy(Vector2f(-delta, 0.0f));
		}
	}
}

Vector2f UIScrollPane::getBasePosition(const String& widgetId)
{
	auto widget = tryGetWidget(widgetId);
	if (widget) {
		return widget->getPosition() + scrollPos - getPosition();
	} else {
		return Vector2f();
	}
}

Vector2f UIScrollPane::getLayoutOriginPosition() const
{
	return getPosition() - scrollPos.floor();
}

void UIScrollPane::scrollToShow(Rect4f rect, bool center)
{
	auto size = getSize();

	float maxX = rect.getLeft();
	float minX = rect.getRight() - size.x;
	float maxY = rect.getTop();
	float minY = rect.getBottom() - size.y;
	auto target = center ? (rect.getCenter() - 0.5f * size) : scrollPos;
	scrollTo(Vector2f(clamp(target.x, minX, maxX), clamp(target.y, minY, maxY)));
}

float UIScrollPane::getScrollSpeed() const
{
	return scrollSpeed;
}

void UIScrollPane::setRelativeScroll(float position, UIScrollDirection direction)
{
	int axis = direction == UIScrollDirection::Horizontal ? 0 : 1;
	auto target = scrollPos;
	target[axis] = position * contentsSize[axis];
	scrollTo(target);
}

std::optional<float> UIScrollPane::getMaxChildWidth() const
{
	if (scrollHorizontal) {
		return std::optional<float>();
	} else {
		return getSize().x;
	}
}

bool UIScrollPane::ignoreClip() const
{
	return true;
}

void UIScrollPane::onChildrenAdded()
{
	refresh(true);
}

void UIScrollPane::onChildrenRemoved()
{
	refresh(true);
}
<commit_msg>Fix scrolling to new list entities<commit_after>#include "widgets/ui_scroll_pane.h"
#include "ui_style.h"
#include "halley/support/logger.h"

using namespace Halley;

UIScrollPane::UIScrollPane(String id, Vector2f clipSize, UISizer&& sizer, bool scrollHorizontal, bool scrollVertical)
	: UIWidget(std::move(id), Vector2f(), std::move(sizer))
	, clipSize(clipSize)
	, scrollSpeed(50.0f)
	, scrollHorizontal(scrollHorizontal)
	, scrollVertical(scrollVertical)
{
	setHandle(UIEventType::MouseWheel, [this] (const UIEvent& event)
	{
		onMouseWheel(event);
	});

	setHandle(UIEventType::MakeAreaVisible, [this] (const UIEvent& event)
	{
		refresh();
		scrollToShow(event.getRectData() + getBasePosition(event.getSourceId()), false);
	});

	setHandle(UIEventType::MakeAreaVisibleCentered, [this] (const UIEvent& event)
	{
		refresh();
		scrollToShow(event.getRectData() + getBasePosition(event.getSourceId()), true);
	});
}

UIScrollPane::UIScrollPane(Vector2f clipSize, UISizer&& sizer, bool scrollHorizontal, bool scrollVertical)
: UIScrollPane("", clipSize, std::move(sizer), scrollHorizontal, scrollVertical) {

}

Vector2f UIScrollPane::getScrollPosition() const
{
	return scrollPos;
}

Vector2f UIScrollPane::getRelativeScrollPosition() const
{
	return scrollPos / std::max(contentsSize, Vector2f(1.0f, 1.0f));
}

Vector2f UIScrollPane::getRelativeScrollEndPosition() const
{
	return (scrollPos + clipSize) / std::max(contentsSize, Vector2f(1.0f, 1.0f));
}

void UIScrollPane::scrollTo(Vector2f position)
{
	if (scrollHorizontal) {
		scrollPos.x = clamp2(position.x, 0.0f, contentsSize.x - getSize().x);
	}

	if (scrollVertical) {
		scrollPos.y = clamp2(position.y, 0.0f, contentsSize.y - getSize().y);
	}
}

void UIScrollPane::scrollBy(Vector2f delta)
{
	scrollTo(scrollPos + delta);
}

void UIScrollPane::setScrollSpeed(float speed)
{
	scrollSpeed = speed;
}

void UIScrollPane::update(Time t, bool moved)
{
	refresh();
}

bool UIScrollPane::canScroll(UIScrollDirection direction) const
{
	auto contentsSize = UIWidget::getLayoutMinimumSize(false);
	if (direction == UIScrollDirection::Horizontal) {
		return scrollHorizontal && getSize().x < contentsSize.x;
	} else {
		return scrollVertical && getSize().y < contentsSize.y;
	}
}

float UIScrollPane::getCoverageSize(UIScrollDirection direction) const
{
	auto contentsSize = UIWidget::getLayoutMinimumSize(false);
	if (direction == UIScrollDirection::Horizontal) {
		return getSize().x / contentsSize.x;
	} else {
		return getSize().y / contentsSize.y;
	}
}

void UIScrollPane::setScrollWheelEnabled(bool enabled)
{
	scrollWheelEnabled = enabled;
}

bool UIScrollPane::isScrollWheelEnabled() const
{
	return scrollWheelEnabled;
}

void UIScrollPane::refresh(bool force)
{
	if (!scrollHorizontal) {
		clipSize.x = getSize().x;
		scrollPos.x = 0;
	}
	if (!scrollVertical) {
		clipSize.y = getSize().y;
		scrollPos.y = 0;
	}
	contentsSize = UIWidget::getLayoutMinimumSize(false);

	setMouseClip(getRect(), force);
	scrollTo(getScrollPosition());
}

void UIScrollPane::drawChildren(UIPainter& painter) const
{
	auto p = painter.withClip(getRect());
	UIWidget::drawChildren(p);
}

Vector2f UIScrollPane::getLayoutMinimumSize(bool force) const
{
	auto size = UIWidget::getLayoutMinimumSize(false);
	if (scrollHorizontal) {
		size.x = std::min(size.x, clipSize.x);
	}
	if (scrollVertical) {
		size.y = std::min(size.y, clipSize.y);
	}
	return size;
}

bool UIScrollPane::canInteractWithMouse() const
{
	return true;
}

void UIScrollPane::onLayout()
{
	refresh();
}

void UIScrollPane::onMouseWheel(const UIEvent& event)
{
	if (scrollWheelEnabled) {
		const float delta = scrollSpeed * float(event.getIntData());
		if (scrollVertical) {
			scrollBy(Vector2f(0.0f, -delta));
		} else {
			scrollBy(Vector2f(-delta, 0.0f));
		}
	}
}

Vector2f UIScrollPane::getBasePosition(const String& widgetId)
{
	auto widget = tryGetWidget(widgetId);
	if (widget) {
		return widget->getPosition() + scrollPos - getPosition();
	} else {
		return Vector2f();
	}
}

Vector2f UIScrollPane::getLayoutOriginPosition() const
{
	return getPosition() - scrollPos.floor();
}

void UIScrollPane::scrollToShow(Rect4f rect, bool center)
{
	auto size = getSize();

	float maxX = rect.getLeft();
	float minX = rect.getRight() - size.x;
	float maxY = rect.getTop();
	float minY = rect.getBottom() - size.y;
	auto target = center ? (rect.getCenter() - 0.5f * size) : scrollPos;
	scrollTo(Vector2f(clamp(target.x, minX, maxX), clamp(target.y, minY, maxY)));
}

float UIScrollPane::getScrollSpeed() const
{
	return scrollSpeed;
}

void UIScrollPane::setRelativeScroll(float position, UIScrollDirection direction)
{
	int axis = direction == UIScrollDirection::Horizontal ? 0 : 1;
	auto target = scrollPos;
	target[axis] = position * contentsSize[axis];
	scrollTo(target);
}

std::optional<float> UIScrollPane::getMaxChildWidth() const
{
	if (scrollHorizontal) {
		return std::optional<float>();
	} else {
		return getSize().x;
	}
}

bool UIScrollPane::ignoreClip() const
{
	return true;
}

void UIScrollPane::onChildrenAdded()
{
	refresh(true);
}

void UIScrollPane::onChildrenRemoved()
{
	refresh(true);
}
<|endoftext|>


<commit_before>#include "ex14_23.h"
#include <algorithm> // for_each, equal

void StrVec::push_back(const std::string &s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

std::pair<std::string*, std::string*>
StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
    auto data = alloc.allocate(e - b);
    return{ data, std::uninitialized_copy(b, e, data) };
}

void StrVec::free()
{
    if (elements) {
        for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); });
        alloc.deallocate(elements, cap - elements);
    }
}

void StrVec::range_initialize(const std::string *first, const std::string *last)
{
    auto newdata = alloc_n_copy(first, last);
    elements = newdata.first;
    first_free = cap = newdata.second;
}

StrVec::StrVec(const StrVec &rhs)
{
    range_initialize(rhs.begin(), rhs.end());
}

StrVec::StrVec(std::initializer_list<std::string> il)
{
    range_initialize(il.begin(), il.end());
}

StrVec::~StrVec()
{
    free();
}

StrVec& StrVec::operator = (const StrVec &rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

void StrVec::alloc_n_move(size_t new_cap)
{
    auto newdata = alloc.allocate(new_cap);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + new_cap;
}

void StrVec::reallocate()
{
    auto newcapacity = size() ? 2 * size() : 1;
    alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t new_cap)
{
    if (new_cap <= capacity()) return;
    alloc_n_move(new_cap);
}

void StrVec::resize(size_t count)
{
    resize(count, std::string());
}

void StrVec::resize(size_t count, const std::string &s)
{
    if (count > size()) {
        if (count > capacity()) reserve(count * 2);
        for (size_t i = size(); i != count; ++i)
            alloc.construct(first_free++, s);
    }
    else if (count < size()) {
        while (first_free != elements + count)
            alloc.destroy(--first_free);
    }
}

StrVec::StrVec(StrVec &&s) NOEXCEPT : elements(s.elements), first_free(s.first_free), cap(s.cap)
{
    // leave s in a state in which it is safe to run the destructor.
    s.elements = s.first_free = s.cap = nullptr;
}

StrVec& StrVec::operator = (StrVec &&rhs) NOEXCEPT
{
    if (this != &rhs) {
        free();
        elements = rhs.elements;
        first_free = rhs.first_free;
        cap = rhs.cap;
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

bool operator==(const StrVec &lhs, const StrVec &rhs)
{
    return (lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()));
}

bool operator!=(const StrVec &lhs, const StrVec &rhs)
{
    return !(lhs == rhs);
}

bool operator<(const StrVec &lhs, const StrVec &rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(const StrVec &lhs, const StrVec &rhs)
{
    return rhs < lhs;
}

bool operator<=(const StrVec &lhs, const StrVec &rhs)
{
    return !(rhs < lhs);
}

bool operator>=(const StrVec &lhs, const StrVec &rhs)
{
    return !(lhs < rhs);
}

StrVec& StrVec::operator=(std::initializer_list<std::string> il)
{
    *this = StrVec(il);
    return *this;
}
<commit_msg>Update ex14_23.cpp<commit_after>#include "ex14_23.h"
#include <algorithm> // for_each, equal

void StrVec::push_back(const std::string &s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

std::pair<std::string*, std::string*>
StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
    auto data = alloc.allocate(e - b);
    return{ data, std::uninitialized_copy(b, e, data) };
}

void StrVec::free()
{
    if (elements) {
        for_each(elements, first_free, [this](std::string &rhs){ alloc.destroy(&rhs); });
        alloc.deallocate(elements, cap - elements);
    }
}

void StrVec::range_initialize(const std::string *first, const std::string *last)
{
    auto newdata = alloc_n_copy(first, last);
    elements = newdata.first;
    first_free = cap = newdata.second;
}

StrVec::StrVec(const StrVec &rhs)
{
    range_initialize(rhs.begin(), rhs.end());
}

StrVec::StrVec(std::initializer_list<std::string> il)
{
    range_initialize(il.begin(), il.end());
}

StrVec::~StrVec()
{
    free();
}

StrVec& StrVec::operator = (const StrVec &rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

void StrVec::alloc_n_move(size_t new_cap)
{
    auto newdata = alloc.allocate(new_cap);
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + new_cap;
}

void StrVec::reallocate()
{
    auto newcapacity = size() ? 2 * size() : 1;
    alloc_n_move(newcapacity);
}

void StrVec::reserve(size_t new_cap)
{
    if (new_cap <= capacity()) return;
    alloc_n_move(new_cap);
}

void StrVec::resize(size_t count)
{
    resize(count, std::string());
}

void StrVec::resize(size_t count, const std::string &s)
{
    if (count > size()) {
        if (count > capacity()) reserve(count * 2);
        for (size_t i = size(); i != count; ++i)
            alloc.construct(first_free++, s);
    }
    else if (count < size()) {
        while (first_free != elements + count)
            alloc.destroy(--first_free);
    }
}

StrVec::StrVec(StrVec &&s) NOEXCEPT : elements(s.elements), first_free(s.first_free), cap(s.cap)
{
    // leave s in a state in which it is safe to run the destructor.
    s.elements = s.first_free = s.cap = nullptr;
}

StrVec& StrVec::operator = (StrVec &&rhs) NOEXCEPT
{
    if (this != &rhs) {
        free();
        elements = rhs.elements;
        first_free = rhs.first_free;
        cap = rhs.cap;
        rhs.elements = rhs.first_free = rhs.cap = nullptr;
    }
    return *this;
}

bool operator==(const StrVec &lhs, const StrVec &rhs)
{
    return (lhs.size() == rhs.size() && std::equal(lhs.begin(), lhs.end(), rhs.begin()));
}

bool operator!=(const StrVec &lhs, const StrVec &rhs)
{
    return !(lhs == rhs);
}

bool operator<(const StrVec &lhs, const StrVec &rhs)
{
    return std::lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
}

bool operator>(const StrVec &lhs, const StrVec &rhs)
{
    return rhs < lhs;
}

bool operator<=(const StrVec &lhs, const StrVec &rhs)
{
    return !(rhs < lhs);
}

bool operator>=(const StrVec &lhs, const StrVec &rhs)
{
    return !(lhs < rhs);
}

StrVec& StrVec::operator=(std::initializer_list<std::string> il)
{
    auto data = alloc_n_copy(il.begin(), il.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
    return *this;
}
<|endoftext|>


<commit_before>/*!
 * \file util_private_ostream.hpp
 * \brief file util_private_ostream.hpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#pragma once

#include <vector>
#include <iostream>
#include <sstream>
#include <fastuidraw/util/util.hpp>
#include <fastuidraw/util/c_array.hpp>
#include <fastuidraw/glsl/shader_source.hpp>

#include "bounding_box.hpp"

template<typename T>
std::ostream&
operator<<(std::ostream &ostr, const fastuidraw::range_type<T> &obj)
{
  ostr << "[" << obj.m_begin << ", " << obj.m_end << ")";
  return ostr;
}

template<typename T, size_t N>
std::ostream&
operator<<(std::ostream &ostr, const fastuidraw::vecN<T, N> &obj)
{
  ostr << "(";
  for(size_t i = 0; i < N; ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
std::ostream&
operator<<(std::ostream &ostr, fastuidraw::c_array<T> obj)
{
  ostr << "(";
  for(size_t i = 0; i < obj.size(); ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
std::ostream&
operator<<(std::ostream &ostr, const std::vector<T> &obj)
{
  ostr << "(";
  for(size_t i = 0; i < obj.size(); ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
std::ostream&
operator<<(std::ostream &str, const fastuidraw::BoundingBox<T> &obj)
{
  if (obj.empty())
    {
      str << "{}";
    }
  else
    {
      str << "[" << obj.min_point() << " -- " << obj.max_point() << "]";
    }
  return str;
}

template<typename T>
fastuidraw::glsl::ShaderSource&
operator<<(fastuidraw::glsl::ShaderSource &src, const T &obj)
{
  std::ostringstream str;
  str << obj;
  src.add_source(str.str().c_str(), fastuidraw::glsl::ShaderSource::from_string);
  return src;
}
<commit_msg>fastuidraw/private/util_private_ostream: add PrintBytes class and place std::ostream& operator<< methods into namespace std<commit_after>/*!
 * \file util_private_ostream.hpp
 * \brief file util_private_ostream.hpp
 *
 * Copyright 2016 by Intel.
 *
 * Contact: kevin.rogovin@intel.com
 *
 * This Source Code Form is subject to the
 * terms of the Mozilla Public License, v. 2.0.
 * If a copy of the MPL was not distributed with
 * this file, You can obtain one at
 * http://mozilla.org/MPL/2.0/.
 *
 * \author Kevin Rogovin <kevin.rogovin@intel.com>
 *
 */

#pragma once

#include <vector>
#include <iostream>
#include <sstream>
#include <fastuidraw/util/util.hpp>
#include <fastuidraw/util/c_array.hpp>
#include <fastuidraw/glsl/shader_source.hpp>

#include "bounding_box.hpp"

namespace fastuidraw { namespace detail {

class PrintBytes
{
public:
  enum rounding_mode_t
    {
      round_to_highest_unit = 0,
      round_to_mb_or_highest_unit = 1,
      round_to_kb_or_highest_unit = 2,
      do_not_round= 3,
    };

  explicit
  PrintBytes(uint64_t v, enum rounding_mode_t r = round_to_kb_or_highest_unit):
    m_gb(fastuidraw::uint64_unpack_bits(30u, 34u, v)),
    m_mb(fastuidraw::uint64_unpack_bits(20u, 10u, v)),
    m_kb(fastuidraw::uint64_unpack_bits(10u, 10u, v)),
    m_b(fastuidraw::uint64_unpack_bits(0u, 10u, v)),
    m_rounding_mode(r)
  {}

  uint64_t m_gb, m_mb, m_kb, m_b;
  enum rounding_mode_t m_rounding_mode;
};

}}

namespace std {
inline
ostream&
operator<<(ostream &str, const fastuidraw::detail::PrintBytes &obj)
{
  bool print_spe(false), print(true);
  char spe(' ');

  if (obj.m_gb && print)
    {
      str << obj.m_gb << "GB";
      print_spe = true;
      print = (obj.m_rounding_mode > fastuidraw::detail::PrintBytes::round_to_highest_unit);
    }

  if (obj.m_mb && print)
    {
      if (print_spe)
        {
          str << spe;
        }
      str << obj.m_mb << "MB";
      print_spe = true;
      print = (obj.m_rounding_mode > fastuidraw::detail::PrintBytes::round_to_mb_or_highest_unit);
    }

  if (obj.m_kb && print)
    {
      if (print_spe)
        {
          str << spe;
        }
      str << obj.m_kb << "KB";
      print_spe = true;
      print = (obj.m_rounding_mode > fastuidraw::detail::PrintBytes::round_to_kb_or_highest_unit);
    }

  if (obj.m_b && print)
    {
      if (print_spe)
        {
          str << spe;
        }
      str << obj.m_b << "B";
    }
  return str;
}

template<typename T>
ostream&
operator<<(ostream &ostr, const fastuidraw::range_type<T> &obj)
{
  ostr << "[" << obj.m_begin << ", " << obj.m_end << ")";
  return ostr;
}

template<typename T, size_t N>
ostream&
operator<<(ostream &ostr, const fastuidraw::vecN<T, N> &obj)
{
  ostr << "(";
  for(size_t i = 0; i < N; ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
ostream&
operator<<(ostream &ostr, fastuidraw::c_array<T> obj)
{
  ostr << "(";
  for(size_t i = 0; i < obj.size(); ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
ostream&
operator<<(ostream &ostr, const vector<T> &obj)
{
  ostr << "(";
  for(size_t i = 0; i < obj.size(); ++i)
    {
      if (i != 0)
        {
          ostr << ", ";
        }
      ostr << obj[i];
    }
  ostr << ")";
  return ostr;
}

template<typename T>
ostream&
operator<<(ostream &str, const fastuidraw::BoundingBox<T> &obj)
{
  if (obj.empty())
    {
      str << "{}";
    }
  else
    {
      str << "[" << obj.min_point() << " -- " << obj.max_point() << "]";
    }
  return str;
}
}

template<typename T>
fastuidraw::glsl::ShaderSource&
operator<<(fastuidraw::glsl::ShaderSource &src, const T &obj)
{
  std::ostringstream str;
  str << obj;
  src.add_source(str.str().c_str(), fastuidraw::glsl::ShaderSource::from_string);
  return src;
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee &dso; Dynamic Shared Object Tests
///
/// @author Nick LeRoy <nleroy@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include <ironbee/hash.h>

#include "ironbee_config_auto.h"

#include "gtest/gtest.h"
#include "gtest/gtest-spi.h"

#include <ironbee/types.h>
#include <ironbee/dso.h>

#include "test_util_dso.h"

#include <stdexcept>

class TestIBUtilDso : public ::testing::Test
{
public:
    TestIBUtilDso( ) : m_dso(NULL) { };

    ~TestIBUtilDso( )
    {
        DsoClose( );
    }

    virtual void SetUp()
    {
        ib_status_t rc = ib_mpool_create(&m_pool, NULL, NULL);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize mpool.");
        }
    }

    virtual void TearDown()
    {
        ib_mpool_destroy(m_pool);
    }

    ib_status_t DsoOpen(const char *file)
    {
        return ib_dso_open(&m_dso, file, m_pool);
    }
    ib_status_t DsoClose( void )
    {
        ib_status_t rc = IB_OK;
        if (m_dso != NULL) {
            rc = ib_dso_close(m_dso);
            m_dso = NULL;
        }
        return rc;
    }
    ib_status_t DsoSymFind(const char *name, ib_dso_sym_t **sym)
    {
        return ib_dso_sym_find(sym, m_dso, name);
    }

protected:
    ib_mpool_t    *m_pool;
    ib_dso_t      *m_dso;
};

TEST_F(TestIBUtilDso, test_open)
{
    {
        SCOPED_TRACE("test_open: normal");
        ib_status_t rc;
        rc = DsoOpen(".libs/libtest_util_dso_lib.so");
        ASSERT_EQ(IB_OK, rc);

        rc = DsoClose( );
        ASSERT_EQ(IB_OK, rc);
    }

    {
        SCOPED_TRACE("test_open: does not exist");
        ib_status_t rc;
        rc = DsoOpen(".libs/libtest_doesnotexist.so");
        ASSERT_EQ(IB_EINVAL, rc);

        rc = DsoClose( );
        ASSERT_EQ(IB_OK, rc);
    }

}

TEST_F(TestIBUtilDso, test_sym_find)
{
    ib_status_t   rc;
    ib_dso_sym_t *sym;

    rc = DsoOpen(".libs/libtest_util_dso_lib.so");
    ASSERT_EQ(IB_OK, rc);

    {
        SCOPED_TRACE("test_sym_find: does not exist");
        rc = DsoSymFind("does_not_exit", &sym);
        ASSERT_EQ(IB_ENOENT, rc);
    }

    {
        SCOPED_TRACE("test_sym_find: normal");
        rc = DsoSymFind("ib_test_util_dso_getfns", &sym);
        ASSERT_EQ(IB_OK, rc);
    }

    rc = DsoClose( );
    ASSERT_EQ(IB_OK, rc);
}

TEST_F(TestIBUtilDso, test_lib)
{
    ib_status_t              rc;
    ib_dso_sym_t            *sym;
    ib_test_dso_getfns_fn_t  getfns;
    ib_test_util_dso_fns_t  *fns;
    ib_test_util_dso_data_t *data;
    int                      num;
    const char              *str;

    rc = DsoOpen(".libs/libtest_util_dso_lib.so");
    ASSERT_EQ(IB_OK, rc);

    rc = DsoSymFind("ib_test_util_dso_getfns", &sym);
    ASSERT_EQ(IB_OK, rc);

    getfns = (ib_test_dso_getfns_fn_t)sym;
    rc = getfns(&fns);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_create(&data, m_pool, 3);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(3, num);

    rc = fns->fn_setnum(data, 666);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(666, num);

    rc = fns->fn_getstr(data, &str);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_STREQ(NULL, str);

    rc = fns->fn_setstr(data, "abc123");
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getstr(data, &str);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_STREQ("abc123", str);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(666, num);

    rc = fns->fn_destroy(data);
    ASSERT_EQ(IB_OK, rc);

    rc = DsoClose( );
    ASSERT_EQ(IB_OK, rc);
}
<commit_msg>test_util_dso.cc: Strip trailing whitespace.<commit_after>//////////////////////////////////////////////////////////////////////////////
// Licensed to Qualys, Inc. (QUALYS) under one or more
// contributor license agreements.  See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// QUALYS licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License.  You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//////////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////////
/// @file
/// @brief IronBee &dso; Dynamic Shared Object Tests
///
/// @author Nick LeRoy <nleroy@qualys.com>
//////////////////////////////////////////////////////////////////////////////

#include <ironbee/hash.h>

#include "ironbee_config_auto.h"

#include "gtest/gtest.h"
#include "gtest/gtest-spi.h"

#include <ironbee/types.h>
#include <ironbee/dso.h>

#include "test_util_dso.h"

#include <stdexcept>

class TestIBUtilDso : public ::testing::Test
{
public:
    TestIBUtilDso( ) : m_dso(NULL) { };

    ~TestIBUtilDso( )
    {
        DsoClose( );
    }

    virtual void SetUp()
    {
        ib_status_t rc = ib_mpool_create(&m_pool, NULL, NULL);
        if (rc != IB_OK) {
            throw std::runtime_error("Could not initialize mpool.");
        }
    }

    virtual void TearDown()
    {
        ib_mpool_destroy(m_pool);
    }

    ib_status_t DsoOpen(const char *file)
    {
        return ib_dso_open(&m_dso, file, m_pool);
    }
    ib_status_t DsoClose( void )
    {
        ib_status_t rc = IB_OK;
        if (m_dso != NULL) {
            rc = ib_dso_close(m_dso);
            m_dso = NULL;
        }
        return rc;
    }
    ib_status_t DsoSymFind(const char *name, ib_dso_sym_t **sym)
    {
        return ib_dso_sym_find(sym, m_dso, name);
    }

protected:
    ib_mpool_t    *m_pool;
    ib_dso_t      *m_dso;
};

TEST_F(TestIBUtilDso, test_open)
{
    {
        SCOPED_TRACE("test_open: normal");
        ib_status_t rc;
        rc = DsoOpen(".libs/libtest_util_dso_lib.so");
        ASSERT_EQ(IB_OK, rc);

        rc = DsoClose( );
        ASSERT_EQ(IB_OK, rc);
    }

    {
        SCOPED_TRACE("test_open: does not exist");
        ib_status_t rc;
        rc = DsoOpen(".libs/libtest_doesnotexist.so");
        ASSERT_EQ(IB_EINVAL, rc);

        rc = DsoClose( );
        ASSERT_EQ(IB_OK, rc);
    }

}

TEST_F(TestIBUtilDso, test_sym_find)
{
    ib_status_t   rc;
    ib_dso_sym_t *sym;

    rc = DsoOpen(".libs/libtest_util_dso_lib.so");
    ASSERT_EQ(IB_OK, rc);

    {
        SCOPED_TRACE("test_sym_find: does not exist");
        rc = DsoSymFind("does_not_exit", &sym);
        ASSERT_EQ(IB_ENOENT, rc);
    }

    {
        SCOPED_TRACE("test_sym_find: normal");
        rc = DsoSymFind("ib_test_util_dso_getfns", &sym);
        ASSERT_EQ(IB_OK, rc);
    }

    rc = DsoClose( );
    ASSERT_EQ(IB_OK, rc);
}

TEST_F(TestIBUtilDso, test_lib)
{
    ib_status_t              rc;
    ib_dso_sym_t            *sym;
    ib_test_dso_getfns_fn_t  getfns;
    ib_test_util_dso_fns_t  *fns;
    ib_test_util_dso_data_t *data;
    int                      num;
    const char              *str;

    rc = DsoOpen(".libs/libtest_util_dso_lib.so");
    ASSERT_EQ(IB_OK, rc);

    rc = DsoSymFind("ib_test_util_dso_getfns", &sym);
    ASSERT_EQ(IB_OK, rc);

    getfns = (ib_test_dso_getfns_fn_t)sym;
    rc = getfns(&fns);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_create(&data, m_pool, 3);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(3, num);

    rc = fns->fn_setnum(data, 666);
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(666, num);

    rc = fns->fn_getstr(data, &str);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_STREQ(NULL, str);

    rc = fns->fn_setstr(data, "abc123");
    ASSERT_EQ(IB_OK, rc);

    rc = fns->fn_getstr(data, &str);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_STREQ("abc123", str);

    rc = fns->fn_getnum(data, &num);
    ASSERT_EQ(IB_OK, rc);
    ASSERT_EQ(666, num);

    rc = fns->fn_destroy(data);
    ASSERT_EQ(IB_OK, rc);

    rc = DsoClose( );
    ASSERT_EQ(IB_OK, rc);
}
<|endoftext|>