<commit_before>#ifndef option_types_hh_INCLUDED
#define option_types_hh_INCLUDED

#include "exception.hh"
#include "string.hh"
#include "units.hh"
#include "coord.hh"
#include "array_view.hh"
#include "id_map.hh"

#include <tuple>
#include <vector>

namespace Kakoune
{

inline String option_to_string(StringView opt) { return opt.str(); }
inline void option_from_string(StringView str, String& opt) { opt = str.str(); }

inline String option_to_string(int opt) { return to_string(opt); }
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }
inline bool option_add(int& opt, int val) { opt += val; return val != 0; }

inline String option_to_string(bool opt) { return opt ? "true" : "false"; }
inline void option_from_string(StringView str, bool& opt)
{
    if (str == "true" or str == "yes")
        opt = true;
    else if (str == "false" or str == "no")
        opt = false;
    else
        throw runtime_error("boolean values are either true, yes, false or no");
}

constexpr char list_separator = ':';

template<typename T, MemoryDomain domain>
String option_to_string(const Vector<T, domain>& opt)
{
    String res;
    for (size_t i = 0; i < opt.size(); ++i)
    {
        res += escape(option_to_string(opt[i]), list_separator, '\\');
        if (i != opt.size() - 1)
            res += list_separator;
    }
    return res;
}

template<typename T, MemoryDomain domain>
void option_from_string(StringView str, Vector<T, domain>& opt)
{
    opt.clear();
    Vector<String> elems = split(str, list_separator, '\\');
    for (auto& elem: elems)
    {
        T opt_elem;
        option_from_string(elem, opt_elem);
        opt.push_back(opt_elem);
    }
}

template<typename T, MemoryDomain domain>
bool option_add(Vector<T, domain>& opt, const Vector<T, domain>& vec)
{
    std::copy(vec.begin(), vec.end(), back_inserter(opt));
    return not vec.empty();
}

template<typename Value, MemoryDomain domain>
String option_to_string(const IdMap<Value, domain>& opt)
{
    String res;
    for (auto it = begin(opt); it != end(opt); ++it)
    {
        if (it != begin(opt))
            res += list_separator;
        String elem = escape(option_to_string(it->key), '=', '\\') + "=" +
                      escape(option_to_string(it->value), '=', '\\');
        res += escape(elem, list_separator, '\\');
    }
    return res;
}

template<typename Value, MemoryDomain domain>
void option_from_string(StringView str, IdMap<Value, domain>& opt)
{
    opt.clear();
    for (auto& elem : split(str, list_separator, '\\'))
    {
        Vector<String> pair_str = split(elem, '=', '\\');
        if (pair_str.size() != 2)
            throw runtime_error("map option expects key=value");
        String key;
        Value value;
        option_from_string(pair_str[0], key);
        option_from_string(pair_str[1], value);
        opt.append({ std::move(key), std::move(value) });
    }
}

constexpr char tuple_separator = '|';

template<size_t I, typename... Types>
struct TupleOptionDetail
{
    static String to_string(const std::tuple<Types...>& opt)
    {
        return TupleOptionDetail<I-1, Types...>::to_string(opt) +
               tuple_separator + escape(option_to_string(std::get<I>(opt)), tuple_separator, '\\');
    }

    static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
    {
        option_from_string(elems[I], std::get<I>(opt));
        TupleOptionDetail<I-1, Types...>::from_string(elems, opt);
    }
};

template<typename... Types>
struct TupleOptionDetail<0, Types...>
{
    static String to_string(const std::tuple<Types...>& opt)
    {
        return option_to_string(std::get<0>(opt));
    }

    static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
    {
        option_from_string(elems[0], std::get<0>(opt));
    }
};

template<typename... Types>
String option_to_string(const std::tuple<Types...>& opt)
{
    return TupleOptionDetail<sizeof...(Types)-1, Types...>::to_string(opt);
}

template<typename... Types>
void option_from_string(StringView str, std::tuple<Types...>& opt)
{
    auto elems = split(str, tuple_separator, '\\');
    if (elems.size() != sizeof...(Types))
        throw runtime_error(elems.size() < sizeof...(Types) ?
                              "not enough elements in tuple"
                            : "to many elements in tuple");
    TupleOptionDetail<sizeof...(Types)-1, Types...>::from_string(elems, opt);
}

template<typename RealType, typename ValueType>
inline String option_to_string(const StronglyTypedNumber<RealType, ValueType>& opt)
{
    return to_string(opt);
}

template<typename RealType, typename ValueType>
inline void option_from_string(StringView str, StronglyTypedNumber<RealType, ValueType>& opt)
{
     opt = StronglyTypedNumber<RealType, ValueType>{str_to_int(str)};
}

template<typename RealType, typename ValueType>
inline bool option_add(StronglyTypedNumber<RealType, ValueType>& opt,
                       StronglyTypedNumber<RealType, ValueType> val)
{
    opt += val;
    return val != 0;
}

template<typename T>
bool option_add(T&, const T&)
{
    throw runtime_error("no add operation supported for this option type");
}

template<typename EffectiveType, typename LineType, typename ColumnType>
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
{
    auto vals = split(str, ',');
    if (vals.size() != 2)
        throw runtime_error("expected <line>,<column>");
    opt.line = str_to_int(vals[0]);
    opt.column = str_to_int(vals[1]);
}

template<typename EffectiveType, typename LineType, typename ColumnType>
inline String option_to_string(const LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
{
    return format("{},{}", opt.line, opt.column);
}

enum YesNoAsk
{
    Yes,
    No,
    Ask
};

inline String option_to_string(YesNoAsk opt)
{
    switch (opt)
    {
        case Yes: return "yes";
        case No:  return "no";
        case Ask: return "ask";
    }
    kak_assert(false);
    return "ask";
}

inline void option_from_string(StringView str, YesNoAsk& opt)
{
    if (str == "yes" or str == "true")
        opt = Yes;
    else if (str == "no" or str == "false")
        opt = No;
    else if (str == "ask")
        opt = Ask;
    else
        throw runtime_error(format("invalid value '{}', expected yes, no or ask", str));
}

}

#endif // option_types_hh_INCLUDED
<commit_msg>Support :set -add on strings, using concatenation<commit_after>#ifndef option_types_hh_INCLUDED
#define option_types_hh_INCLUDED

#include "exception.hh"
#include "string.hh"
#include "units.hh"
#include "coord.hh"
#include "array_view.hh"
#include "id_map.hh"

#include <tuple>
#include <vector>

namespace Kakoune
{

inline String option_to_string(StringView opt) { return opt.str(); }
inline void option_from_string(StringView str, String& opt) { opt = str.str(); }
inline bool option_add(String& opt, const String& val) { opt += val; return not val.empty(); }

inline String option_to_string(int opt) { return to_string(opt); }
inline void option_from_string(StringView str, int& opt) { opt = str_to_int(str); }
inline bool option_add(int& opt, int val) { opt += val; return val != 0; }

inline String option_to_string(bool opt) { return opt ? "true" : "false"; }
inline void option_from_string(StringView str, bool& opt)
{
    if (str == "true" or str == "yes")
        opt = true;
    else if (str == "false" or str == "no")
        opt = false;
    else
        throw runtime_error("boolean values are either true, yes, false or no");
}

constexpr char list_separator = ':';

template<typename T, MemoryDomain domain>
String option_to_string(const Vector<T, domain>& opt)
{
    String res;
    for (size_t i = 0; i < opt.size(); ++i)
    {
        res += escape(option_to_string(opt[i]), list_separator, '\\');
        if (i != opt.size() - 1)
            res += list_separator;
    }
    return res;
}

template<typename T, MemoryDomain domain>
void option_from_string(StringView str, Vector<T, domain>& opt)
{
    opt.clear();
    Vector<String> elems = split(str, list_separator, '\\');
    for (auto& elem: elems)
    {
        T opt_elem;
        option_from_string(elem, opt_elem);
        opt.push_back(opt_elem);
    }
}

template<typename T, MemoryDomain domain>
bool option_add(Vector<T, domain>& opt, const Vector<T, domain>& vec)
{
    std::copy(vec.begin(), vec.end(), back_inserter(opt));
    return not vec.empty();
}

template<typename Value, MemoryDomain domain>
String option_to_string(const IdMap<Value, domain>& opt)
{
    String res;
    for (auto it = begin(opt); it != end(opt); ++it)
    {
        if (it != begin(opt))
            res += list_separator;
        String elem = escape(option_to_string(it->key), '=', '\\') + "=" +
                      escape(option_to_string(it->value), '=', '\\');
        res += escape(elem, list_separator, '\\');
    }
    return res;
}

template<typename Value, MemoryDomain domain>
void option_from_string(StringView str, IdMap<Value, domain>& opt)
{
    opt.clear();
    for (auto& elem : split(str, list_separator, '\\'))
    {
        Vector<String> pair_str = split(elem, '=', '\\');
        if (pair_str.size() != 2)
            throw runtime_error("map option expects key=value");
        String key;
        Value value;
        option_from_string(pair_str[0], key);
        option_from_string(pair_str[1], value);
        opt.append({ std::move(key), std::move(value) });
    }
}

constexpr char tuple_separator = '|';

template<size_t I, typename... Types>
struct TupleOptionDetail
{
    static String to_string(const std::tuple<Types...>& opt)
    {
        return TupleOptionDetail<I-1, Types...>::to_string(opt) +
               tuple_separator + escape(option_to_string(std::get<I>(opt)), tuple_separator, '\\');
    }

    static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
    {
        option_from_string(elems[I], std::get<I>(opt));
        TupleOptionDetail<I-1, Types...>::from_string(elems, opt);
    }
};

template<typename... Types>
struct TupleOptionDetail<0, Types...>
{
    static String to_string(const std::tuple<Types...>& opt)
    {
        return option_to_string(std::get<0>(opt));
    }

    static void from_string(ConstArrayView<String> elems, std::tuple<Types...>& opt)
    {
        option_from_string(elems[0], std::get<0>(opt));
    }
};

template<typename... Types>
String option_to_string(const std::tuple<Types...>& opt)
{
    return TupleOptionDetail<sizeof...(Types)-1, Types...>::to_string(opt);
}

template<typename... Types>
void option_from_string(StringView str, std::tuple<Types...>& opt)
{
    auto elems = split(str, tuple_separator, '\\');
    if (elems.size() != sizeof...(Types))
        throw runtime_error(elems.size() < sizeof...(Types) ?
                              "not enough elements in tuple"
                            : "to many elements in tuple");
    TupleOptionDetail<sizeof...(Types)-1, Types...>::from_string(elems, opt);
}

template<typename RealType, typename ValueType>
inline String option_to_string(const StronglyTypedNumber<RealType, ValueType>& opt)
{
    return to_string(opt);
}

template<typename RealType, typename ValueType>
inline void option_from_string(StringView str, StronglyTypedNumber<RealType, ValueType>& opt)
{
     opt = StronglyTypedNumber<RealType, ValueType>{str_to_int(str)};
}

template<typename RealType, typename ValueType>
inline bool option_add(StronglyTypedNumber<RealType, ValueType>& opt,
                       StronglyTypedNumber<RealType, ValueType> val)
{
    opt += val;
    return val != 0;
}

template<typename T>
bool option_add(T&, const T&)
{
    throw runtime_error("no add operation supported for this option type");
}

template<typename EffectiveType, typename LineType, typename ColumnType>
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
{
    auto vals = split(str, ',');
    if (vals.size() != 2)
        throw runtime_error("expected <line>,<column>");
    opt.line = str_to_int(vals[0]);
    opt.column = str_to_int(vals[1]);
}

template<typename EffectiveType, typename LineType, typename ColumnType>
inline String option_to_string(const LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
{
    return format("{},{}", opt.line, opt.column);
}

enum YesNoAsk
{
    Yes,
    No,
    Ask
};

inline String option_to_string(YesNoAsk opt)
{
    switch (opt)
    {
        case Yes: return "yes";
        case No:  return "no";
        case Ask: return "ask";
    }
    kak_assert(false);
    return "ask";
}

inline void option_from_string(StringView str, YesNoAsk& opt)
{
    if (str == "yes" or str == "true")
        opt = Yes;
    else if (str == "no" or str == "false")
        opt = No;
    else if (str == "ask")
        opt = Ask;
    else
        throw runtime_error(format("invalid value '{}', expected yes, no or ask", str));
}

}

#endif // option_types_hh_INCLUDED
<|endoftext|>


<commit_before>#include "pybind_main.h"

std::vector<std::pair<std::string, std::complex<double>>> simulate(const py::dict &options) {

  qflex::QflexInput input;

  // Check options for circuit
  switch(options.contains("circuit_filename") + options.contains("circuit")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'circuit_filename' or 'circuit' must be specified" << std::endl;
      return {};
  }

  // Check options for ordering
  switch(options.contains("ordering_filename") + options.contains("ordering")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'ordering_filename' or 'ordering' must be specified" << std::endl;
      return {};
  }

  // Check options for grid
  switch(options.contains("grid_filename") + options.contains("grid")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'grid_filename' or 'grid' must be specified" << std::endl;
      return {};
  }

  // Temporary streams
  std::ifstream fs_circuit_data;
  std::ifstream fs_ordering_data;

  // Get circuit
  if(options.contains("circuit_filename")) {
    fs_circuit_data.open(options["circuit_filename"].cast<std::string>());
    if(not fs_circuit_data.good()) {
      std::cerr << "ERROR: cannot open file: " << options["circuit_filename"].cast<std::string>() << "." << std::endl;
      return {};
    }
    input.circuit_data = &fs_circuit_data;
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get ordering
  if(options.contains("ordering_filename")) {
    fs_ordering_data.open(options["ordering_filename"].cast<std::string>());
    if(not fs_ordering_data.good()) {
      std::cerr << "ERROR: cannot open file: " << options["ordering_filename"].cast<std::string>() << "." << std::endl;
      return {};
    }
    input.ordering_data = &fs_ordering_data;
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get grid
  if(options.contains("grid_filename")) {
    input.grid.load(options["grid_filename"].cast<std::string>());
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get auto_depth
  std::size_t auto_depth;
  if(options.contains("circuit_filename")) {
    auto_depth = qflex::compute_depth(std::ifstream(options["circuit_filename"].cast<std::string>()));
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get depth
  if(options.contains("depth")) {
    input.K = options["depth"].cast<int>();
    if(input.K != auto_depth) {
      std::cerr << "WARNING: user-provided depth (" << input.K << ") differs from the auto-computed depth (" << auto_depth << ")." << std::endl;
      return {};
    }
  } else input.K = auto_depth;

  // Setting initial and final circuit states.
  if(options.contains("initial_state"))
    input.initial_state = options["initial_state"].cast<std::string>();

  if(options.contains("final_state"))
    input.initial_state = options["final_state"].cast<std::string>();

  // Evaluating circuit.
  std::vector<std::pair<std::string, std::complex<double>>> amplitudes =
      qflex::EvaluateCircuit(&input);

  return amplitudes;

}
<commit_msg>Fix bug.<commit_after>#include "pybind_main.h"

std::vector<std::pair<std::string, std::complex<double>>> simulate(const py::dict &options) {

  qflex::QflexInput input;

  // Check options for circuit
  switch(options.contains("circuit_filename") + options.contains("circuit")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'circuit_filename' or 'circuit' must be specified" << std::endl;
      return {};
  }

  // Check options for ordering
  switch(options.contains("ordering_filename") + options.contains("ordering")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'ordering_filename' or 'ordering' must be specified" << std::endl;
      return {};
  }

  // Check options for grid
  switch(options.contains("grid_filename") + options.contains("grid")) {
    case 0:
    case 2:
      std::cerr << "ERROR: either 'grid_filename' or 'grid' must be specified" << std::endl;
      return {};
  }

  // Temporary streams
  std::ifstream fs_circuit_data;
  std::ifstream fs_ordering_data;

  // Get circuit
  if(options.contains("circuit_filename")) {
    fs_circuit_data.open(options["circuit_filename"].cast<std::string>());
    if(not fs_circuit_data.good()) {
      std::cerr << "ERROR: cannot open file: " << options["circuit_filename"].cast<std::string>() << "." << std::endl;
      return {};
    }
    input.circuit_data = &fs_circuit_data;
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get ordering
  if(options.contains("ordering_filename")) {
    fs_ordering_data.open(options["ordering_filename"].cast<std::string>());
    if(not fs_ordering_data.good()) {
      std::cerr << "ERROR: cannot open file: " << options["ordering_filename"].cast<std::string>() << "." << std::endl;
      return {};
    }
    input.ordering_data = &fs_ordering_data;
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get grid
  if(options.contains("grid_filename")) {
    input.grid.load(options["grid_filename"].cast<std::string>());
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get auto_depth
  std::size_t auto_depth;
  if(options.contains("circuit_filename")) {
    auto_depth = qflex::compute_depth(std::ifstream(options["circuit_filename"].cast<std::string>()));
  } else {
    std::cerr << "ERROR: not yet implemented." << std::endl;
    return {};
  }

  // Get depth
  if(options.contains("depth")) {
    input.K = options["depth"].cast<int>();
    if(input.K != auto_depth) {
      std::cerr << "WARNING: user-provided depth (" << input.K << ") differs from the auto-computed depth (" << auto_depth << ")." << std::endl;
      return {};
    }
  } else input.K = auto_depth;

  // Setting initial and final circuit states.
  if(options.contains("initial_state"))
    input.initial_state = options["initial_state"].cast<std::string>();

  if(options.contains("final_state"))
    input.final_state = options["final_state"].cast<std::string>();

  // Evaluating circuit.
  std::vector<std::pair<std::string, std::complex<double>>> amplitudes =
      qflex::EvaluateCircuit(&input);

  return amplitudes;

}
<|endoftext|>


<commit_before>#include "pyjstypeconv.h"
#include "pyjsobject.h"
#include <cassert>
#include <iostream>
v8::Local<v8::Value> PyToJs(PyObject *pyObject) {
    Nan::EscapableHandleScope scope;
    if (pyObject == nullptr) {
        return scope.Escape(Nan::Undefined());
    } else if (pyObject == Py_None) {
        return scope.Escape(Nan::Null());
    } else if (PyUnicode_CheckExact(pyObject)) {
        Py_ssize_t size;
        char *str = PyUnicode_AsUTF8AndSize(pyObject, &size);
        return scope.Escape(Nan::New(str, size).ToLocalChecked());
    } else if (PyBool_Check(pyObject)) {
        return scope.Escape(Nan::New<v8::Boolean>(pyObject == Py_True));
    } else if (PyFloat_CheckExact(pyObject)) {
        return scope.Escape(Nan::New<v8::Number>(PyFloat_AsDouble(pyObject)));
    } else if (PyList_CheckExact(pyObject)) {
        v8::Local<v8::Array> jsArr = Nan::New<v8::Array>();
        Py_ssize_t size = PyList_Size(pyObject);
        for (ssize_t i = 0; i < size; i++) {
            jsArr->Set(i, PyToJs(PyList_GetItem(pyObject, i)));
        }
        return scope.Escape(jsArr);
    } else if (PyDict_CheckExact(pyObject)) {
        v8::Local<v8::Object> jsObject = Nan::New<v8::Object>();
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        while (PyDict_Next(pyObject, &pos, &key, &value)) {
            jsObject->Set(PyToJs(key), PyToJs(value));
        }
        return scope.Escape(jsObject);
    } else if (PyCallable_Check(pyObject)/* || PyObject_HasAttrString(pyObject, "__call__")*/) {
        Py_INCREF(pyObject);
        v8::Local<v8::Object> jsObject = PyjsObject::NewInstance(pyObject);

        const int argc = 1;
        v8::Local<v8::Value> argv[] = { jsObject };
        v8::Local<v8::Function> makeFunction = Nan::New(PyjsObject::makeFunction);
        v8::Local<v8::Function> result = makeFunction->Call(jsObject, argc, argv).As<v8::Function>();

        return scope.Escape(result);
    }
    Py_INCREF(pyObject);
    return scope.Escape(PyjsObject::NewInstance(pyObject));
}

// return new reference
PyObject *JsToPy(v8::Local<v8::Value> jsValue) {
    Nan::HandleScope scope;
    if (jsValue->IsObject()) {
        v8::Local<v8::Object> jsObject = jsValue->ToObject();
        PyjsObject *object = PyjsObject::UnWrap(jsObject);
        if (object) {
            // just unwrap and return
            return object->GetObject();
        }
    }
    if (jsValue->IsNull()) {
        Py_INCREF(Py_None);
        return Py_None;
    } else if (jsValue->IsString()) {
        v8::Local<v8::String> jsString = jsValue->ToString();
        v8::String::Utf8Value utf8String(jsString);
        return PyUnicode_FromStringAndSize(*utf8String, jsString->Utf8Length());
    } else if (jsValue->IsTrue()) {
        Py_INCREF(Py_True);
        return Py_True;
    } else if (jsValue->IsFalse()) {
        Py_INCREF(Py_False);
        return Py_False;
    } else if (jsValue->IsNumber()) {
        return PyFloat_FromDouble(jsValue->NumberValue());
    } else if (jsValue->IsArray()) {
        v8::Local<v8::Array> jsArr = jsValue.As<v8::Array>();
        PyObject *pyArr = PyList_New(jsArr->Length());
        for (ssize_t i = 0; i < jsArr->Length(); i++) {
            int result = PyList_SetItem(pyArr, i, JsToPy(jsArr->Get(i)));
            assert(result != -1);
        }
        return pyArr;
    } else if (jsValue->IsFunction()) {
        assert(0);
    } else if (jsValue->IsObject()) { // must be after null, array, function
        v8::Local<v8::Object> jsObject = jsValue->ToObject();
        PyObject *pyDict = PyDict_New();
        v8::Local<v8::Array> props = Nan::GetOwnPropertyNames(jsObject).ToLocalChecked();
        for (ssize_t i = 0; i < props->Length(); i++) {
            v8::Local<v8::Value> jsKey = props->Get(i);
            v8::Local<v8::Value> jsValue = jsObject->Get(jsKey);
            PyObject *pyKey = JsToPy(jsKey);
            PyObject *pyValue = JsToPy(jsValue);
            int result = PyDict_SetItem(pyDict, pyKey, pyValue);
            assert(result != -1);
            Py_DECREF(pyKey);
            Py_DECREF(pyValue);
        }
        return pyDict;
    } else if (jsValue->IsUndefined()) {
        return nullptr;
    }
    assert(0); // should not reach here
}
<commit_msg>= = remove unused comment<commit_after>#include "pyjstypeconv.h"
#include "pyjsobject.h"
#include <cassert>
#include <iostream>
v8::Local<v8::Value> PyToJs(PyObject *pyObject) {
    Nan::EscapableHandleScope scope;
    if (pyObject == nullptr) {
        return scope.Escape(Nan::Undefined());
    } else if (pyObject == Py_None) {
        return scope.Escape(Nan::Null());
    } else if (PyUnicode_CheckExact(pyObject)) {
        Py_ssize_t size;
        char *str = PyUnicode_AsUTF8AndSize(pyObject, &size);
        return scope.Escape(Nan::New(str, size).ToLocalChecked());
    } else if (PyBool_Check(pyObject)) {
        return scope.Escape(Nan::New<v8::Boolean>(pyObject == Py_True));
    } else if (PyFloat_CheckExact(pyObject)) {
        return scope.Escape(Nan::New<v8::Number>(PyFloat_AsDouble(pyObject)));
    } else if (PyList_CheckExact(pyObject)) {
        v8::Local<v8::Array> jsArr = Nan::New<v8::Array>();
        Py_ssize_t size = PyList_Size(pyObject);
        for (ssize_t i = 0; i < size; i++) {
            jsArr->Set(i, PyToJs(PyList_GetItem(pyObject, i)));
        }
        return scope.Escape(jsArr);
    } else if (PyDict_CheckExact(pyObject)) {
        v8::Local<v8::Object> jsObject = Nan::New<v8::Object>();
        PyObject *key, *value;
        Py_ssize_t pos = 0;
        while (PyDict_Next(pyObject, &pos, &key, &value)) {
            jsObject->Set(PyToJs(key), PyToJs(value));
        }
        return scope.Escape(jsObject);
    } else if (PyCallable_Check(pyObject)) {
        Py_INCREF(pyObject);
        v8::Local<v8::Object> jsObject = PyjsObject::NewInstance(pyObject);

        const int argc = 1;
        v8::Local<v8::Value> argv[] = { jsObject };
        v8::Local<v8::Function> makeFunction = Nan::New(PyjsObject::makeFunction);
        v8::Local<v8::Function> result = makeFunction->Call(jsObject, argc, argv).As<v8::Function>();

        return scope.Escape(result);
    }
    Py_INCREF(pyObject);
    return scope.Escape(PyjsObject::NewInstance(pyObject));
}

// return new reference
PyObject *JsToPy(v8::Local<v8::Value> jsValue) {
    Nan::HandleScope scope;
    if (jsValue->IsObject()) {
        v8::Local<v8::Object> jsObject = jsValue->ToObject();
        PyjsObject *object = PyjsObject::UnWrap(jsObject);
        if (object) {
            // just unwrap and return
            return object->GetObject();
        }
    }
    if (jsValue->IsNull()) {
        Py_INCREF(Py_None);
        return Py_None;
    } else if (jsValue->IsString()) {
        v8::Local<v8::String> jsString = jsValue->ToString();
        v8::String::Utf8Value utf8String(jsString);
        return PyUnicode_FromStringAndSize(*utf8String, jsString->Utf8Length());
    } else if (jsValue->IsTrue()) {
        Py_INCREF(Py_True);
        return Py_True;
    } else if (jsValue->IsFalse()) {
        Py_INCREF(Py_False);
        return Py_False;
    } else if (jsValue->IsNumber()) {
        return PyFloat_FromDouble(jsValue->NumberValue());
    } else if (jsValue->IsArray()) {
        v8::Local<v8::Array> jsArr = jsValue.As<v8::Array>();
        PyObject *pyArr = PyList_New(jsArr->Length());
        for (ssize_t i = 0; i < jsArr->Length(); i++) {
            int result = PyList_SetItem(pyArr, i, JsToPy(jsArr->Get(i)));
            assert(result != -1);
        }
        return pyArr;
    } else if (jsValue->IsFunction()) {
        assert(0);
    } else if (jsValue->IsObject()) { // must be after null, array, function
        v8::Local<v8::Object> jsObject = jsValue->ToObject();
        PyObject *pyDict = PyDict_New();
        v8::Local<v8::Array> props = Nan::GetOwnPropertyNames(jsObject).ToLocalChecked();
        for (ssize_t i = 0; i < props->Length(); i++) {
            v8::Local<v8::Value> jsKey = props->Get(i);
            v8::Local<v8::Value> jsValue = jsObject->Get(jsKey);
            PyObject *pyKey = JsToPy(jsKey);
            PyObject *pyValue = JsToPy(jsValue);
            int result = PyDict_SetItem(pyDict, pyKey, pyValue);
            assert(result != -1);
            Py_DECREF(pyKey);
            Py_DECREF(pyValue);
        }
        return pyDict;
    } else if (jsValue->IsUndefined()) {
        return nullptr;
    }
    assert(0); // should not reach here
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <string.h>
#include <osgDB/Field>

using namespace osgDB;
using namespace std;

Field::Field()
{
    _init();
}

Field::Field(const Field& ic)
{
    _copy(ic);
}

Field::~Field()
{
    _free();
}

Field& Field::operator = (const Field& ic)
{
    if (this==&ic) return *this;
    _free();
    _copy(ic);
    return *this;
}

void Field::_free()
{
    // free all data
    if (_fieldCache) delete [] _fieldCache;

    _init();

}

void Field::_init()
{

    _fieldCacheCapacity = 256;
    _fieldCacheSize = 0;
    _fieldCache = NULL;

    _fieldType = UNINITIALISED;

    _withinQuotes = false;

    _noNestedBrackets = 0;

}

void Field::_copy(const Field& ic)
{

    // copy string cache.
    if (ic._fieldCache)
    {
        _fieldCacheCapacity = ic._fieldCacheCapacity;
        _fieldCacheSize = ic._fieldCacheSize;
        _fieldCache = new char [_fieldCacheCapacity];
        strncpy(_fieldCache,ic._fieldCache,_fieldCacheCapacity);
    }
    else
    {
        _fieldCacheCapacity = 0;
        _fieldCacheSize = 0;
        _fieldCache = NULL;
    }

    _fieldType = ic._fieldType;

    _withinQuotes = ic._withinQuotes;

    _noNestedBrackets = ic._noNestedBrackets;
}

void Field::setWithinQuotes(bool withinQuotes)
{
    _withinQuotes=withinQuotes;
    _fieldType = UNINITIALISED;
}

bool Field::getWithinQuotes()
{
    return _withinQuotes;
}

void Field::setNoNestedBrackets(int no)
{
    _noNestedBrackets=no;
}

int Field::getNoNestedBrackets()
{
    return _noNestedBrackets;
}

const char* Field::getStr() const
{
    if (_fieldCacheSize!=0) return _fieldCache;
    else return NULL;
}

char* Field::takeStr()
{
    char* field = _fieldCache;

    _fieldCache = NULL;
    _fieldCacheSize = 0;

    _fieldType = UNINITIALISED;
    _withinQuotes = false;

    return field;
}

void Field::reset()
{
    _fieldCacheSize = 0;
    if (_fieldCache)
    {
        _fieldCache[_fieldCacheSize] = 0;
    }

    _withinQuotes = false;
    _noNestedBrackets = 0;
}

void Field::addChar(char c)
{
    if (_fieldCache==NULL)
    {
        if (_fieldCacheCapacity<MIN_CACHE_SIZE) _fieldCacheCapacity=MIN_CACHE_SIZE;
        _fieldCache = new char[_fieldCacheCapacity];
        memset(_fieldCache,0,_fieldCacheCapacity);
        _fieldCacheSize = 0;
    }
    else if (_fieldCacheSize>=_fieldCacheCapacity-1)
    {
        if (_fieldCacheCapacity<MIN_CACHE_SIZE) _fieldCacheCapacity=MIN_CACHE_SIZE;
        while (_fieldCacheSize>=_fieldCacheCapacity-1) _fieldCacheCapacity *= 2;
        char* tmp_str = _fieldCache;
        _fieldCache = new char[_fieldCacheCapacity];
        memset(_fieldCache,0,_fieldCacheCapacity);
        strncpy(_fieldCache,tmp_str,_fieldCacheSize);
        delete [] tmp_str;

    }
    _fieldCache[_fieldCacheSize++] = c;
    _fieldCache[_fieldCacheSize] = 0;
    _fieldType = UNINITIALISED;
}

Field::FieldType Field::getFieldType() const
{
    if (_fieldType==UNINITIALISED && _fieldCache)
    {
        _fieldType = calculateFieldType(_fieldCache,_withinQuotes);
    }
    return _fieldType;
}

bool Field::isValid() const
{
    if (_fieldCacheSize>0  && !_withinQuotes) return true;
    else return false;
}

bool Field::isOpenBracket() const
{
    if (_fieldCacheSize==1) return _fieldCache[0]=='{';
    else return false;
}

bool Field::isCloseBracket() const
{
    if (_fieldCacheSize==1) return _fieldCache[0]=='}';
    else return false;
}

bool Field::isWord() const
{
    getFieldType();
    return (_fieldType==WORD);
}

bool Field::matchWord(const char* str) const
{
    getFieldType();
    return _fieldType==WORD && strcmp(_fieldCache,str)==0;
}

bool Field::matchWord(const char* str,int noCharacters) const
{
    getFieldType();
    return _fieldType==WORD && strncmp(_fieldCache,str,noCharacters)==0;
}

bool Field::isString() const
{
    return getNoCharacters()!=0;
}

bool Field::matchString(const char* str) const
{
    return strcmp(_fieldCache,str)==0;
}

bool Field::matchString(const char* str,int noCharacters) const
{
    return strncmp(_fieldCache,str,noCharacters)==0;
}

bool Field::isQuotedString() const
{
    return _withinQuotes;
}

bool Field::isInt() const
{
    getFieldType();
    return _fieldType==INTEGER;
}

bool Field::matchInt(int i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        return strtol(_fieldCache,NULL,0)==i;
    }
    else
    {
        return false;
    }
}

bool Field::getInt(int& i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        i = strtol(_fieldCache,NULL,0);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::isUInt() const
{
    getFieldType();
    return _fieldType==INTEGER;
}

bool Field::matchUInt(unsigned int i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        return (unsigned int) strtoul(_fieldCache,NULL,0)==i;
    }
    else
    {
        return false;
    }
}

bool Field::getUInt(unsigned int& i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        i = strtoul(_fieldCache,NULL,0);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::isFloat() const
{
    getFieldType();
    return _fieldType==REAL || _fieldType==INTEGER;
}

bool Field::matchFloat(float f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        return (float)atof(_fieldCache)==f;
    }
    else
    {
        return false;
    }
}

bool Field::getFloat(float& f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        f = (float)atof(_fieldCache);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::getFloat(double& f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        f = atof(_fieldCache);
        return true;
    }
    else
    {
        return false;
    }
}

Field::FieldType Field::calculateFieldType(const char* str,bool withinQuotes)
{
    if (str==NULL) return BLANK;
    if (*str==0) return BLANK;

    if (withinQuotes) return STRING;

    bool hadPlusMinus = false;
    bool hadDecimalPlace = false;
    bool hadExponent = false;
    bool couldBeInt = true;
    bool couldBeFloat = true;
    int noZeroToNine = 0;

    const char* ptr = str;

    // check if could be a hex number.
    if (strncmp(ptr,"0x",2)==0)
    {
        // skip over leading 0x, and then go through rest of string
        // checking to make sure all values are 0...9 or a..f.
        ptr+=2;
        while (
               *ptr!=0 &&
               ((*ptr>='0' && *ptr<='9') ||
                (*ptr>='a' && *ptr<='f') ||
                (*ptr>='A' && *ptr<='F'))
              )
        {
            ++ptr;
        }

        // got to end of string without failure, therefore must be a hex integer.
        if (*ptr==0) return INTEGER;
    }

    ptr = str;
    // check if a float or an int.
    while (*ptr!=0 && couldBeFloat)
    {
        if (*ptr=='+' || *ptr=='-')
        {
            if (hadPlusMinus)
            {
                couldBeInt = false;
                couldBeFloat = false;
            } else hadPlusMinus = true;
        }
        else if (*ptr>='0' && *ptr<='9')
        {
            noZeroToNine++;
        }
        else if (*ptr=='.')
        {
            if (hadDecimalPlace)
            {
                couldBeInt = false;
                couldBeFloat = false;
            }
            else
            {
                hadDecimalPlace = true;
                couldBeInt = false;
            }
        }
        else if (*ptr=='e' || *ptr=='E')
        {
            if (hadExponent || noZeroToNine==0)
            {
                couldBeInt = false;
                couldBeFloat = false;
            }
            else
            {
                hadExponent = true;
                couldBeInt = false;
                hadDecimalPlace = false;
                hadPlusMinus = false;
                noZeroToNine=0;
            }
        }
        else
        {
            couldBeInt = false;
            couldBeFloat = false;
        }
        ++ptr;
    }

    if (couldBeInt && noZeroToNine>0) return INTEGER;
    if (couldBeFloat && noZeroToNine>0) return REAL;
    if (str[0]=='{') return OPEN_BRACKET;
    if (str[0]=='}') return CLOSE_BRACKET;
    return WORD;
}
<commit_msg>Introduce a custom atof function that always assumes data comes in form 10.10 with the full stop used as a decimal place.<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * OpenSceneGraph Public License for more details.
*/
#include <string.h>
#include <math.h>
#include <osg/Notify>
#include <osgDB/Field>

using namespace osgDB;
using namespace std;

double osg_atof(const char* str)
{
    const char* ptr = str;

    // check if could be a hex number.
    if (strncmp(ptr,"0x",2)==0)
    {

        double value = 0.0;

        // skip over leading 0x, and then go through rest of string
        // checking to make sure all values are 0...9 or a..f.
        ptr+=2;
        while (
               *ptr!=0 &&
               ((*ptr>='0' && *ptr<='9') ||
                (*ptr>='a' && *ptr<='f') ||
                (*ptr>='A' && *ptr<='F'))
              )
        {
            if (*ptr>='0' && *ptr<='9') value = value*16.0 + double(*ptr-'0');
            else if (*ptr>='a' && *ptr<='f') value = value*16.0 + double(*ptr-'a'+10);
            else if (*ptr>='A' && *ptr<='F') value = value*16.0 + double(*ptr-'A'+10);
            ++ptr;
        }

        // osg::notify(osg::NOTICE)<<"Read "<<str<<" result = "<<value<<std::endl;
        return value;
    }

    ptr = str;

    bool    hadDecimal[2];
    double  value[2];
    double  sign[2];
    double  decimalMultiplier[2];

    hadDecimal[0] = hadDecimal[1] = false;
    sign[0] = sign[1] = 1.0;
    value[0] = value[1] = 0.0;
    decimalMultiplier[0] = decimalMultiplier[1] = 0.1;
    int pos = 0;

    // compute mantissa and exponent parts
    while (*ptr!=0 && pos<2)
    {
        if (*ptr=='+')
        {
            sign[pos] = 1.0;
        }
        else if (*ptr=='-')
        {
            sign[pos] = -1.0;
        }
        else if (*ptr>='0' && *ptr<='9')
        {
            if (!hadDecimal[pos])
            {
                value[pos] = value[pos]*10.0 + double(*ptr-'0');
            }
            else
            {
                value[pos] = value[pos] + decimalMultiplier[pos] * double(*ptr-'0');
                decimalMultiplier[pos] *= 0.1;
            }
        }
        else if (*ptr=='.')
        {
            hadDecimal[pos] = true;
        }
        else if (*ptr=='e' || *ptr=='E')
        {
            if (pos==1) break;

            pos = 1;
        }
        else
        {
            break;
        }
        ++ptr;
    }

    if (pos==0)
    {
        // osg::notify(osg::NOTICE)<<"Read "<<str<<" result = "<<value[0]*sign[0]<<std::endl;
        return value[0]*sign[0];
    }
    else
    {
        double mantissa = value[0]*sign[0];
        double exponent = value[1]*sign[1];
        //osg::notify(osg::NOTICE)<<"Read "<<str<<" mantissa = "<<mantissa<<" exponent="<<exponent<<" result = "<<mantissa*pow(10.0,exponent)<<std::endl;
        return mantissa*pow(10.0,exponent);
    }
}

Field::Field()
{
    _init();
}

Field::Field(const Field& ic)
{
    _copy(ic);
}

Field::~Field()
{
    _free();
}

Field& Field::operator = (const Field& ic)
{
    if (this==&ic) return *this;
    _free();
    _copy(ic);
    return *this;
}

void Field::_free()
{
    // free all data
    if (_fieldCache) delete [] _fieldCache;

    _init();

}

void Field::_init()
{

    _fieldCacheCapacity = 256;
    _fieldCacheSize = 0;
    _fieldCache = NULL;

    _fieldType = UNINITIALISED;

    _withinQuotes = false;

    _noNestedBrackets = 0;

}

void Field::_copy(const Field& ic)
{

    // copy string cache.
    if (ic._fieldCache)
    {
        _fieldCacheCapacity = ic._fieldCacheCapacity;
        _fieldCacheSize = ic._fieldCacheSize;
        _fieldCache = new char [_fieldCacheCapacity];
        strncpy(_fieldCache,ic._fieldCache,_fieldCacheCapacity);
    }
    else
    {
        _fieldCacheCapacity = 0;
        _fieldCacheSize = 0;
        _fieldCache = NULL;
    }

    _fieldType = ic._fieldType;

    _withinQuotes = ic._withinQuotes;

    _noNestedBrackets = ic._noNestedBrackets;
}

void Field::setWithinQuotes(bool withinQuotes)
{
    _withinQuotes=withinQuotes;
    _fieldType = UNINITIALISED;
}

bool Field::getWithinQuotes()
{
    return _withinQuotes;
}

void Field::setNoNestedBrackets(int no)
{
    _noNestedBrackets=no;
}

int Field::getNoNestedBrackets()
{
    return _noNestedBrackets;
}

const char* Field::getStr() const
{
    if (_fieldCacheSize!=0) return _fieldCache;
    else return NULL;
}

char* Field::takeStr()
{
    char* field = _fieldCache;

    _fieldCache = NULL;
    _fieldCacheSize = 0;

    _fieldType = UNINITIALISED;
    _withinQuotes = false;

    return field;
}

void Field::reset()
{
    _fieldCacheSize = 0;
    if (_fieldCache)
    {
        _fieldCache[_fieldCacheSize] = 0;
    }

    _withinQuotes = false;
    _noNestedBrackets = 0;
}

void Field::addChar(char c)
{
    if (_fieldCache==NULL)
    {
        if (_fieldCacheCapacity<MIN_CACHE_SIZE) _fieldCacheCapacity=MIN_CACHE_SIZE;
        _fieldCache = new char[_fieldCacheCapacity];
        memset(_fieldCache,0,_fieldCacheCapacity);
        _fieldCacheSize = 0;
    }
    else if (_fieldCacheSize>=_fieldCacheCapacity-1)
    {
        if (_fieldCacheCapacity<MIN_CACHE_SIZE) _fieldCacheCapacity=MIN_CACHE_SIZE;
        while (_fieldCacheSize>=_fieldCacheCapacity-1) _fieldCacheCapacity *= 2;
        char* tmp_str = _fieldCache;
        _fieldCache = new char[_fieldCacheCapacity];
        memset(_fieldCache,0,_fieldCacheCapacity);
        strncpy(_fieldCache,tmp_str,_fieldCacheSize);
        delete [] tmp_str;

    }
    _fieldCache[_fieldCacheSize++] = c;
    _fieldCache[_fieldCacheSize] = 0;
    _fieldType = UNINITIALISED;
}

Field::FieldType Field::getFieldType() const
{
    if (_fieldType==UNINITIALISED && _fieldCache)
    {
        _fieldType = calculateFieldType(_fieldCache,_withinQuotes);
    }
    return _fieldType;
}

bool Field::isValid() const
{
    if (_fieldCacheSize>0  && !_withinQuotes) return true;
    else return false;
}

bool Field::isOpenBracket() const
{
    if (_fieldCacheSize==1) return _fieldCache[0]=='{';
    else return false;
}

bool Field::isCloseBracket() const
{
    if (_fieldCacheSize==1) return _fieldCache[0]=='}';
    else return false;
}

bool Field::isWord() const
{
    getFieldType();
    return (_fieldType==WORD);
}

bool Field::matchWord(const char* str) const
{
    getFieldType();
    return _fieldType==WORD && strcmp(_fieldCache,str)==0;
}

bool Field::matchWord(const char* str,int noCharacters) const
{
    getFieldType();
    return _fieldType==WORD && strncmp(_fieldCache,str,noCharacters)==0;
}

bool Field::isString() const
{
    return getNoCharacters()!=0;
}

bool Field::matchString(const char* str) const
{
    return strcmp(_fieldCache,str)==0;
}

bool Field::matchString(const char* str,int noCharacters) const
{
    return strncmp(_fieldCache,str,noCharacters)==0;
}

bool Field::isQuotedString() const
{
    return _withinQuotes;
}

bool Field::isInt() const
{
    getFieldType();
    return _fieldType==INTEGER;
}

bool Field::matchInt(int i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        return strtol(_fieldCache,NULL,0)==i;
    }
    else
    {
        return false;
    }
}

bool Field::getInt(int& i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        i = strtol(_fieldCache,NULL,0);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::isUInt() const
{
    getFieldType();
    return _fieldType==INTEGER;
}

bool Field::matchUInt(unsigned int i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        return (unsigned int) strtoul(_fieldCache,NULL,0)==i;
    }
    else
    {
        return false;
    }
}

bool Field::getUInt(unsigned int& i) const
{
    getFieldType();
    if (_fieldType==INTEGER)
    {
        i = strtoul(_fieldCache,NULL,0);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::isFloat() const
{
    getFieldType();
    return _fieldType==REAL || _fieldType==INTEGER;
}

bool Field::matchFloat(float f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        return (float)osg_atof(_fieldCache)==f;
    }
    else
    {
        return false;
    }
}

bool Field::getFloat(float& f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        f = (float)osg_atof(_fieldCache);
        return true;
    }
    else
    {
        return false;
    }
}

bool Field::getFloat(double& f) const
{
    getFieldType();
    if (_fieldType==REAL || _fieldType==INTEGER)
    {
        f = osg_atof(_fieldCache);
        return true;
    }
    else
    {
        return false;
    }
}

Field::FieldType Field::calculateFieldType(const char* str,bool withinQuotes)
{
    if (str==NULL) return BLANK;
    if (*str==0) return BLANK;

    if (withinQuotes) return STRING;

    bool hadPlusMinus = false;
    bool hadDecimalPlace = false;
    bool hadExponent = false;
    bool couldBeInt = true;
    bool couldBeFloat = true;
    int noZeroToNine = 0;

    const char* ptr = str;

    // check if could be a hex number.
    if (strncmp(ptr,"0x",2)==0)
    {
        // skip over leading 0x, and then go through rest of string
        // checking to make sure all values are 0...9 or a..f.
        ptr+=2;
        while (
               *ptr!=0 &&
               ((*ptr>='0' && *ptr<='9') ||
                (*ptr>='a' && *ptr<='f') ||
                (*ptr>='A' && *ptr<='F'))
              )
        {
            ++ptr;
        }

        // got to end of string without failure, therefore must be a hex integer.
        if (*ptr==0) return INTEGER;
    }

    ptr = str;
    // check if a float or an int.
    while (*ptr!=0 && couldBeFloat)
    {
        if (*ptr=='+' || *ptr=='-')
        {
            if (hadPlusMinus)
            {
                couldBeInt = false;
                couldBeFloat = false;
            } else hadPlusMinus = true;
        }
        else if (*ptr>='0' && *ptr<='9')
        {
            noZeroToNine++;
        }
        else if (*ptr=='.')
        {
            if (hadDecimalPlace)
            {
                couldBeInt = false;
                couldBeFloat = false;
            }
            else
            {
                hadDecimalPlace = true;
                couldBeInt = false;
            }
        }
        else if (*ptr=='e' || *ptr=='E')
        {
            if (hadExponent || noZeroToNine==0)
            {
                couldBeInt = false;
                couldBeFloat = false;
            }
            else
            {
                hadExponent = true;
                couldBeInt = false;
                hadDecimalPlace = false;
                hadPlusMinus = false;
                noZeroToNine=0;
            }
        }
        else
        {
            couldBeInt = false;
            couldBeFloat = false;
        }
        ++ptr;
    }

    if (couldBeInt && noZeroToNine>0) return INTEGER;
    if (couldBeFloat && noZeroToNine>0) return REAL;
    if (str[0]=='{') return OPEN_BRACKET;
    if (str[0]=='}') return CLOSE_BRACKET;
    return WORD;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011-2013 The Bitcoin Core developers
// Copyright (c) 2014-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/qrdialog.h>
#include <qt/forms/ui_qrdialog.h>

#include <qt/syscoinunits.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/walletmodel.h>

#include <QClipboard>
#include <QDrag>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QPixmap>
#if QT_VERSION < 0x050000
#include <QUrl>
#endif

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h> /* for USE_QRCODE */
#endif

#ifdef USE_QRCODE
#include <qrencode.h>
#endif

QRGeneralImageWidget::QRGeneralImageWidget(QWidget *parent):
    QLabel(parent), contextMenu(0)
{
    contextMenu = new QMenu(this);
    QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
    connect(saveImageAction, &QAction::triggered, this, &QRGeneralImageWidget::saveImage);
    contextMenu->addAction(saveImageAction);
    QAction *copyImageAction = new QAction(tr("&Copy Image"), this);
    connect(copyImageAction, &QAction::triggered, this, &QRGeneralImageWidget::copyImage);
    contextMenu->addAction(copyImageAction);
}

QImage QRGeneralImageWidget::exportImage()
{
    if(!pixmap())
        return QImage();
    return pixmap()->toImage();
}

void QRGeneralImageWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton && pixmap())
    {
        event->accept();
        QMimeData *mimeData = new QMimeData;
        mimeData->setImageData(exportImage());

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->exec();
    } else {
        QLabel::mousePressEvent(event);
    }
}

void QRGeneralImageWidget::saveImage()
{
    if(!pixmap())
        return;
    QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), NULL);
    if (!fn.isEmpty())
    {
        exportImage().save(fn);
    }
}

void QRGeneralImageWidget::copyImage()
{
    if(!pixmap())
        return;
    QApplication::clipboard()->setImage(exportImage());
}

void QRGeneralImageWidget::contextMenuEvent(QContextMenuEvent *event)
{
    if(!pixmap())
        return;
    contextMenu->exec(event->globalPos());
}

QRDialog::QRDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::QRDialog),
    model(0)
{
    ui->setupUi(this);

#ifndef USE_QRCODE
    ui->button_saveImage->setVisible(false);
    ui->lblQRCode->setVisible(false);
#endif

    connect(ui->button_saveImage, &QPushButton::clicked, ui->lblQRCode, &QRGeneralImageWidget::saveImage);
}

QRDialog::~QRDialog()
{
    delete ui;
}

void QRDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if (model)
        connect(model, &OptionsModel::displayUnitChanged, this, &QRDialog::update());

    // update the display unit if necessary
    update();
}

void QRDialog::setInfo(QString strWindowtitle, QString strQRCode, QString strTextInfo, QString strQRCodeTitle)
{
    this->strWindowtitle = strWindowtitle;
    this->strQRCode = strQRCode;
    this->strTextInfo = strTextInfo;
    this->strQRCodeTitle = strQRCodeTitle;
    update();
}

void QRDialog::update()
{
    if(!model)
        return;

    setWindowTitle(strWindowtitle);
    ui->button_saveImage->setEnabled(false);
    ui->outUri->setText(strTextInfo);

#ifdef USE_QRCODE
    // Create QR-code
    ui->lblQRCode->setText("");
    if(!strQRCode.isEmpty())
    {
        QRcode *code = QRcode_encodeString(strQRCode.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
        if (!code)
        {
            ui->lblQRCode->setText(tr("Error creating QR Code."));
            return;
        }
        ui->lblQRCode->setToolTip(strQRCode);
        QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
        myImage.fill(0xffffff);
        unsigned char *p = code->data;
        for (int y = 0; y < code->width; y++)
        {
            for (int x = 0; x < code->width; x++)
            {
                myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                p++;
            }
        }
        QRcode_free(code);

        ui->labelQRCodeTitle->setText(strQRCodeTitle);
        ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
        ui->button_saveImage->setEnabled(true);
    }
#endif
}
<commit_msg>fix build<commit_after>// Copyright (c) 2011-2013 The Bitcoin Core developers
// Copyright (c) 2014-2018 The Syscoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <qt/qrdialog.h>
#include <qt/forms/ui_qrdialog.h>

#include <qt/syscoinunits.h>
#include <qt/guiconstants.h>
#include <qt/guiutil.h>
#include <qt/optionsmodel.h>
#include <qt/walletmodel.h>

#include <QClipboard>
#include <QDrag>
#include <QMenu>
#include <QMimeData>
#include <QMouseEvent>
#include <QPixmap>
#if QT_VERSION < 0x050000
#include <QUrl>
#endif

#if defined(HAVE_CONFIG_H)
#include <config/syscoin-config.h> /* for USE_QRCODE */
#endif

#ifdef USE_QRCODE
#include <qrencode.h>
#endif

QRGeneralImageWidget::QRGeneralImageWidget(QWidget *parent):
    QLabel(parent), contextMenu(0)
{
    contextMenu = new QMenu(this);
    QAction *saveImageAction = new QAction(tr("&Save Image..."), this);
    connect(saveImageAction, &QAction::triggered, this, &QRGeneralImageWidget::saveImage);
    contextMenu->addAction(saveImageAction);
    QAction *copyImageAction = new QAction(tr("&Copy Image"), this);
    connect(copyImageAction, &QAction::triggered, this, &QRGeneralImageWidget::copyImage);
    contextMenu->addAction(copyImageAction);
}

QImage QRGeneralImageWidget::exportImage()
{
    if(!pixmap())
        return QImage();
    return pixmap()->toImage();
}

void QRGeneralImageWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton && pixmap())
    {
        event->accept();
        QMimeData *mimeData = new QMimeData;
        mimeData->setImageData(exportImage());

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->exec();
    } else {
        QLabel::mousePressEvent(event);
    }
}

void QRGeneralImageWidget::saveImage()
{
    if(!pixmap())
        return;
    QString fn = GUIUtil::getSaveFileName(this, tr("Save QR Code"), QString(), tr("PNG Image (*.png)"), NULL);
    if (!fn.isEmpty())
    {
        exportImage().save(fn);
    }
}

void QRGeneralImageWidget::copyImage()
{
    if(!pixmap())
        return;
    QApplication::clipboard()->setImage(exportImage());
}

void QRGeneralImageWidget::contextMenuEvent(QContextMenuEvent *event)
{
    if(!pixmap())
        return;
    contextMenu->exec(event->globalPos());
}

QRDialog::QRDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::QRDialog),
    model(0)
{
    ui->setupUi(this);

#ifndef USE_QRCODE
    ui->button_saveImage->setVisible(false);
    ui->lblQRCode->setVisible(false);
#endif

    connect(ui->button_saveImage, &QPushButton::clicked, ui->lblQRCode, &QRGeneralImageWidget::saveImage);
}

QRDialog::~QRDialog()
{
    delete ui;
}

void QRDialog::setModel(OptionsModel *model)
{
    this->model = model;

    if (model)
        connect(model, &OptionsModel::displayUnitChanged, this, &QRDialog::update);

    // update the display unit if necessary
    update();
}

void QRDialog::setInfo(QString strWindowtitle, QString strQRCode, QString strTextInfo, QString strQRCodeTitle)
{
    this->strWindowtitle = strWindowtitle;
    this->strQRCode = strQRCode;
    this->strTextInfo = strTextInfo;
    this->strQRCodeTitle = strQRCodeTitle;
    update();
}

void QRDialog::update()
{
    if(!model)
        return;

    setWindowTitle(strWindowtitle);
    ui->button_saveImage->setEnabled(false);
    ui->outUri->setText(strTextInfo);

#ifdef USE_QRCODE
    // Create QR-code
    ui->lblQRCode->setText("");
    if(!strQRCode.isEmpty())
    {
        QRcode *code = QRcode_encodeString(strQRCode.toUtf8().constData(), 0, QR_ECLEVEL_L, QR_MODE_8, 1);
        if (!code)
        {
            ui->lblQRCode->setText(tr("Error creating QR Code."));
            return;
        }
        ui->lblQRCode->setToolTip(strQRCode);
        QImage myImage = QImage(code->width + 8, code->width + 8, QImage::Format_RGB32);
        myImage.fill(0xffffff);
        unsigned char *p = code->data;
        for (int y = 0; y < code->width; y++)
        {
            for (int x = 0; x < code->width; x++)
            {
                myImage.setPixel(x + 4, y + 4, ((*p & 1) ? 0x0 : 0xffffff));
                p++;
            }
        }
        QRcode_free(code);

        ui->labelQRCodeTitle->setText(strQRCodeTitle);
        ui->lblQRCode->setPixmap(QPixmap::fromImage(myImage).scaled(300, 300));
        ui->button_saveImage->setEnabled(true);
    }
#endif
}
<|endoftext|>


<commit_before>#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <fstream>
#include <iostream>
#include <set>
#include <string>

#include "boost/algorithm/string.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"

#include "snap.h"
#include "distance.h"

const std::string prefix = "Data/";
const std::string output_path = "../tmp/";
const std::string suffix = "-Combined.txt";
const int max_input_size = 1000000;

void remove_zero_keys(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results) {
  std::vector<std::string> zero_keys;
  for (auto it0 = results.begin(); it0 != results.end(); ++it0) {
    bool all_zero = true;
    for (auto it1 = results.begin(); it1 != results.end(); ++it1) {
      std::string key0 = it0 -> first;
      std::string key1 = it1 -> first;
      if (key0 <= key1 && results[key0][key1].first != 0) {
        all_zero = false;
        break;
      } else if(results[key1][key0].first != 0) {
        all_zero = false;
        break;
      }
    }
    if (all_zero) {
      zero_keys.push_back(it0 -> first);
    }
  }
  for (std::string zero_key : zero_keys) {
    for (auto it = results.rbegin(); (it -> first) > zero_key; ++it) {
      (it -> second).erase(zero_key);
    }
    results.erase(zero_key);
  }
}

void output_files(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results,
                  std::string uid, std::string prefix, std::string description) {
  boost::algorithm::trim(description);
  std::string file_description = "";
  if (description != "") {
    file_description = description + "_";
    boost::replace_all(file_description, " ", "_");
  }
  std::string outputMatrixFilePath = output_path + prefix + "_matrix_" + file_description + uid + ".csv";
  std::ofstream outputMatrixFile(outputMatrixFilePath, std::ios::out);
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          outputMatrixFile, false, ',');
  outputMatrixFile.close();
  std::string outputMatrixWithHeadersFilePath = output_path + prefix + "_matrix_with_headers_" + file_description + uid + ".csv";
  std::ofstream outputMatrixWithHeadersFile(outputMatrixWithHeadersFilePath, std::ios::out);
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          outputMatrixWithHeadersFile, true, ',');
  outputMatrixWithHeadersFile.close();
  std::string outputKeyFilePath = output_path + prefix + "_keys_" + file_description + uid + ".csv";
  std::ofstream outputKeyFile(outputKeyFilePath, std::ios::out);
  for (auto it = results.begin(); it != results.end(); ++it) outputKeyFile << it -> first << '\n';
  outputKeyFile.close();

  std::cout << snap::web::create_link(outputMatrixFilePath, "Matching programs matrix (numbers only) " + description) << "
" << std::endl;
  std::cout << snap::web::create_link(outputMatrixWithHeadersFilePath, "Matching programs matrix (with headers) " + description) << "
" << std::endl;
  std::cout << snap::web::create_link(outputKeyFilePath, "Matrix row and column names " + description) << "
" << std::endl;
}

void output_visualization(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results, std::string uid, std::string dt) {
  // first turn the results to just program matches
  std::map<std::string, std::map<std::string, int>> program_matches;
  for (auto it = results.begin(); it != results.end(); ++it) {
    program_matches[it->first] = std::map<std::string, int>();
    for (auto jt = (it -> second).begin(); jt != (it -> second).end(); ++jt) {
      program_matches[it->first][jt -> first] = (jt -> second).first;
    }
  }

  std::map<std::string, std::map<std::string, int>> filtered_program_matches = distance::filter_top(program_matches, 20);

  std::map<std::string, double> sizes = distance::size_pow(program_matches, 1.0/3);

  std::map<std::string, std::map<std::string, double>> distances = distance::distance_inv(program_matches);

  std::string csv = distance::size_distance_to_csv(sizes, distances);

  // std::cout << "
" << csv << "
" << std::endl;
  std::string visualization_file_path = output_path + dt + "_visualization_" + uid + ".csv";
  std::ofstream visualization_file(visualization_file_path, std::ios::out);
  visualization_file << csv;
  visualization_file.close();
  std::cout << snap::web::create_link(visualization_file_path, "Visualization File") << "
" << std::endl;

  std::string json = snap::web::matrix_to_json(csv);
  std::string json_file_name = dt + "_visualization_" + uid + ".json";
  std::string visualization_json_path = output_path + json_file_name;
  std::ofstream visualization_json(visualization_json_path, std::ios::out);
  visualization_json << json;
  visualization_json.close();

  std::cout << "
"
            << ""
            << "Visualization"
            << "
"
            << std::endl;
}

int main() {
  clock_t start_time = std::clock();

  snap::web::print_header();

  // get user input
  int content_length = atoi(getenv("CONTENT_LENGTH"));
  char *input = new char[content_length+1];
  fgets(input, content_length+1, stdin);
  std::string query_string(input);
  delete[] input;
  std::map<std::string, std::string> arguments = snap::web::parse_query_string(query_string);

  // turn inputs into C++ types
  int distance = stoi(arguments["distance"]);
  boost::gregorian::date current_date, from_date, to_date;
  try {
    current_date = snap::date::string_to_date(arguments["from-date"]);
    from_date = snap::date::string_to_date(arguments["from-date"]);
    to_date = snap::date::string_to_date(arguments["to-date"]);
  } catch (snap::date::InvalidDateException &e) {
    std::cout << "" << e.what() << "" << std::endl;
    exit(-1);
  }
  std::vector<std::string> file_list = snap::io::generate_file_names(from_date, to_date, prefix, suffix);

  // process search strings
  std::vector<std::string> search_strings;
  arguments["search-strings"] = snap::web::sanitize_string(arguments["search-strings"]);
  boost::split(search_strings, arguments["search-strings"], boost::is_any_of("\n"));
  // remove empty strings
  auto search_string_iterator = search_strings.begin();
  while (search_string_iterator != search_strings.end()) {
    if (std::all_of(search_string_iterator -> begin() , search_string_iterator -> end(), ::isspace)) {
      search_string_iterator = search_strings.erase(search_string_iterator);
    } else {
      boost::algorithm::trim(*search_string_iterator);
      ++search_string_iterator;
    }
  }
  if (search_strings.size() == 0) {
    std::cout << "" << "Error: There are no search strings." << "" << std::endl;
    exit(-1);
  }
  std::sort(search_strings.begin(), search_strings.end());

  std::vector<snap::Expression> expressions;
  std::set<std::string> pattern_set;
  for (auto it = search_strings.begin(); it != search_strings.end(); ++it) {
    try {
      expressions.emplace_back(*it);
    } catch(snap::ExpressionSyntaxError &e) {
      const char *error_msg = e.what();
      std::cout << "" << error_msg << "" << std::endl;
      delete[] error_msg;
      exit(-1);
    }
    pattern_set.insert(expressions.back().patterns.begin(), expressions.back().patterns.end());
  }
  std::vector<std::string> patterns;
  patterns.insert(patterns.end(), pattern_set.begin(), pattern_set.end());

  // print output for user to verify
  std::cout << "
" << std::endl;
  std::cout << "Search strings:" << "
" << std::endl;
  for (auto it = search_strings.begin(); it != search_strings.end(); ++it) {
    std::cout << *it << "
" << std::endl;
  }
  std::cout << "Distance: " << arguments["distance"] << "
" << std::endl;
  std::cout << "From (inclusive): " << arguments["from-date"] << "
" << std::endl;
  std::cout << "To (exclusive): " << arguments["to-date"] << "
" << std::endl;
  std::cout << "
" << std::endl;

  // initiate result matrix
  std::map<std::string, std::map<std::string, std::pair<int, int>>> results;
  for (auto it0 = expressions.begin(); it0 != expressions.end(); ++it0) {
    results[it0 -> raw_expression] = std::map<std::string, std::pair<int, int>>();
    for (auto it1(it0); it1 != expressions.end(); ++it1) {
      results[it0 -> raw_expression][it1 -> raw_expression] = std::make_pair(0, 0);
    }
  }
  int total_programs_cnt = 0;
  int selected_programs_cnt = 0;

  // run through dates
  std::vector<std::string> missing_files;
  std::vector<std::string> corrupt_files;
  for (auto it = file_list.begin(); it != file_list.end(); ++it) {
    boost::gregorian::date::ymd_type ymd = current_date.year_month_day();
    std::cout << "Processing " << ymd.month << " "
              << ymd.day << ", " << ymd.year
              << "...
" << std::endl;
    if (snap::io::file_exists(*it)) {
      std::vector<snap::Program> programs;
      try {
        programs = snap::io::parse_programs(*it);
      } catch (snap::io::CorruptFileException &e) {
        programs.clear();
        current_date += boost::gregorian::date_duration(1);
        corrupt_files.push_back(*it);
        continue;
      }
      total_programs_cnt += programs.size();
      for (auto p = programs.begin(); p != programs.end(); ++p) {
        ++selected_programs_cnt;
        std::map<std::string, std::vector<int>> raw_match_positions = snap::find(patterns, p -> lower_text);
        std::map<std::string, std::vector<int>> match_positions = evaluate_expressions(expressions, raw_match_positions);
        std::map<std::string, std::map<std::string, int>> cooccurences = snap::pair(match_positions, distance);
        for (auto it0 = cooccurences.begin(); it0 != cooccurences.end(); ++it0) {
          for (auto it1 = (it0 -> second).begin(); it1 != (it0 -> second).end(); ++it1) {
            if (it1 -> second > 0) {
              ++results[it0 -> first][it1 -> first].first;
              results[it0 -> first][it1 -> first].second += it1 -> second;
            }
          }
        }
      }
    } else {
      missing_files.push_back(*it);
    }
    current_date += boost::gregorian::date_duration(1);
  }
  std::cout << "
";
  std::cout << "
" << std::endl;
  snap::web::print_missing_files(missing_files);
  std::cout << "
" << std::endl;
  snap::web::print_corrupt_files(corrupt_files);
  std::cout << "
" << std::endl;

  // print results
  std::cout << "
" << std::endl;
  std::cout << "Selected Programs Count: " << selected_programs_cnt << std::endl;
  std::cout << "Total Programs Count: " << total_programs_cnt << std::endl;
  std::cout << "search_string_1\tsearch_string_2\tmatching_programs_cnt\ttotal_matches_cnt" << std::endl;
  for (auto it0 = results.begin(); it0 != results.end(); ++it0) {
    for (auto it1 = (it0 -> second).begin(); it1 != (it0 -> second).end(); ++it1) {
      std::cout << it0 -> first << '\t' << it1 -> first << '\t'
                << (it1 -> second).first << '\t' << (it1 -> second).second << std::endl;
    }
  }

  std::cout << "\nMatching Programs\n" << std::endl;
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          std::cout, true, '\t');

  std::cout << "\nTotal Matches\n" << std::endl;
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.second; },
                          std::cout, true, '\t');
  std::cout << "
" << std::endl;

  std::cout << "
Output Files
" << std::endl;
  srand(time(NULL));
  std::string random_id = std::to_string(rand());

  output_files(results, random_id, snap::date::date_to_string(from_date), "");
  remove_zero_keys(results);
  output_files(results, random_id, snap::date::date_to_string(from_date), "no zeroes");

  // output for visualization
  output_visualization(results, random_id, snap::date::date_to_string(from_date));

  double duration = (std::clock() - start_time) / (double) CLOCKS_PER_SEC;
  std::cout << "
Time taken (seconds): " << duration << "
" << std::endl;
  snap::web::close_html();
  return 0;
}
<commit_msg>used filtered matches<commit_after>#include <algorithm>
#include <cctype>
#include <cstdlib>
#include <cstdio>
#include <ctime>
#include <fstream>
#include <iostream>
#include <set>
#include <string>

#include "boost/algorithm/string.hpp"
#include "boost/date_time/gregorian/gregorian.hpp"

#include "snap.h"
#include "distance.h"

const std::string prefix = "Data/";
const std::string output_path = "../tmp/";
const std::string suffix = "-Combined.txt";
const int max_input_size = 1000000;

void output_visualization(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results, std::string uid, std::string dt) {
  // first turn the results to just program matches
  std::map<std::string, std::map<std::string, int>> program_matches;
  for (auto it = results.begin(); it != results.end(); ++it) {
    program_matches[it->first] = std::map<std::string, int>();
    for (auto jt = (it -> second).begin(); jt != (it -> second).end(); ++jt) {
      program_matches[it->first][jt -> first] = (jt -> second).first;
    }
  }

  std::map<std::string, std::map<std::string, int>> filtered_program_matches = distance::filter_top(program_matches, 20);

  std::map<std::string, double> sizes = distance::size_pow(filtered_program_matches, 1.0/3);

  std::map<std::string, std::map<std::string, double>> distances = distance::distance_inv(filtered_program_matches);

  std::string csv = distance::size_distance_to_csv(sizes, distances);

  // std::cout << "
" << csv << "
" << std::endl;
  std::string visualization_file_path = output_path + dt + "_visualization_" + uid + ".csv";
  std::ofstream visualization_file(visualization_file_path, std::ios::out);
  visualization_file << csv;
  visualization_file.close();
  std::cout << snap::web::create_link(visualization_file_path, "Visualization File") << "
" << std::endl;

  std::string json = snap::web::matrix_to_json(csv);
  std::string json_file_name = dt + "_visualization_" + uid + ".json";
  std::string visualization_json_path = output_path + json_file_name;
  std::ofstream visualization_json(visualization_json_path, std::ios::out);
  visualization_json << json;
  visualization_json.close();

  std::cout << "
"
            << ""
            << "Visualization"
            << "
"
            << std::endl;
}

void remove_zero_keys(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results) {
  std::vector<std::string> zero_keys;
  for (auto it0 = results.begin(); it0 != results.end(); ++it0) {
    bool all_zero = true;
    for (auto it1 = results.begin(); it1 != results.end(); ++it1) {
      std::string key0 = it0 -> first;
      std::string key1 = it1 -> first;
      if (key0 <= key1 && results[key0][key1].first != 0) {
        all_zero = false;
        break;
      } else if(results[key1][key0].first != 0) {
        all_zero = false;
        break;
      }
    }
    if (all_zero) {
      zero_keys.push_back(it0 -> first);
    }
  }
  for (std::string zero_key : zero_keys) {
    for (auto it = results.rbegin(); (it -> first) > zero_key; ++it) {
      (it -> second).erase(zero_key);
    }
    results.erase(zero_key);
  }
}

void output_files(std::map<std::string, std::map<std::string, std::pair<int, int>>> &results,
                  std::string uid, std::string prefix, std::string description) {
  boost::algorithm::trim(description);
  std::string file_description = "";
  if (description != "") {
    file_description = description + "_";
    boost::replace_all(file_description, " ", "_");
  }
  std::string outputMatrixFilePath = output_path + prefix + "_matrix_" + file_description + uid + ".csv";
  std::ofstream outputMatrixFile(outputMatrixFilePath, std::ios::out);
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          outputMatrixFile, false, ',');
  outputMatrixFile.close();
  std::string outputMatrixWithHeadersFilePath = output_path + prefix + "_matrix_with_headers_" + file_description + uid + ".csv";
  std::ofstream outputMatrixWithHeadersFile(outputMatrixWithHeadersFilePath, std::ios::out);
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          outputMatrixWithHeadersFile, true, ',');
  outputMatrixWithHeadersFile.close();
  std::string outputKeyFilePath = output_path + prefix + "_keys_" + file_description + uid + ".csv";
  std::ofstream outputKeyFile(outputKeyFilePath, std::ios::out);
  for (auto it = results.begin(); it != results.end(); ++it) outputKeyFile << it -> first << '\n';
  outputKeyFile.close();

  std::cout << snap::web::create_link(outputMatrixFilePath, "Matching programs matrix (numbers only) " + description) << "
" << std::endl;
  std::cout << snap::web::create_link(outputMatrixWithHeadersFilePath, "Matching programs matrix (with headers) " + description) << "
" << std::endl;
  std::cout << snap::web::create_link(outputKeyFilePath, "Matrix row and column names " + description) << "
" << std::endl;
}

int main() {
  clock_t start_time = std::clock();

  snap::web::print_header();

  // get user input
  int content_length = atoi(getenv("CONTENT_LENGTH"));
  char *input = new char[content_length+1];
  fgets(input, content_length+1, stdin);
  std::string query_string(input);
  delete[] input;
  std::map<std::string, std::string> arguments = snap::web::parse_query_string(query_string);

  // turn inputs into C++ types
  int distance = stoi(arguments["distance"]);
  boost::gregorian::date current_date, from_date, to_date;
  try {
    current_date = snap::date::string_to_date(arguments["from-date"]);
    from_date = snap::date::string_to_date(arguments["from-date"]);
    to_date = snap::date::string_to_date(arguments["to-date"]);
  } catch (snap::date::InvalidDateException &e) {
    std::cout << "" << e.what() << "" << std::endl;
    exit(-1);
  }
  std::vector<std::string> file_list = snap::io::generate_file_names(from_date, to_date, prefix, suffix);

  // process search strings
  std::vector<std::string> search_strings;
  arguments["search-strings"] = snap::web::sanitize_string(arguments["search-strings"]);
  boost::split(search_strings, arguments["search-strings"], boost::is_any_of("\n"));
  // remove empty strings
  auto search_string_iterator = search_strings.begin();
  while (search_string_iterator != search_strings.end()) {
    if (std::all_of(search_string_iterator -> begin() , search_string_iterator -> end(), ::isspace)) {
      search_string_iterator = search_strings.erase(search_string_iterator);
    } else {
      boost::algorithm::trim(*search_string_iterator);
      ++search_string_iterator;
    }
  }
  if (search_strings.size() == 0) {
    std::cout << "" << "Error: There are no search strings." << "" << std::endl;
    exit(-1);
  }
  std::sort(search_strings.begin(), search_strings.end());

  std::vector<snap::Expression> expressions;
  std::set<std::string> pattern_set;
  for (auto it = search_strings.begin(); it != search_strings.end(); ++it) {
    try {
      expressions.emplace_back(*it);
    } catch(snap::ExpressionSyntaxError &e) {
      const char *error_msg = e.what();
      std::cout << "" << error_msg << "" << std::endl;
      delete[] error_msg;
      exit(-1);
    }
    pattern_set.insert(expressions.back().patterns.begin(), expressions.back().patterns.end());
  }
  std::vector<std::string> patterns;
  patterns.insert(patterns.end(), pattern_set.begin(), pattern_set.end());

  // print output for user to verify
  std::cout << "
" << std::endl;
  std::cout << "Search strings:" << "
" << std::endl;
  for (auto it = search_strings.begin(); it != search_strings.end(); ++it) {
    std::cout << *it << "
" << std::endl;
  }
  std::cout << "Distance: " << arguments["distance"] << "
" << std::endl;
  std::cout << "From (inclusive): " << arguments["from-date"] << "
" << std::endl;
  std::cout << "To (exclusive): " << arguments["to-date"] << "
" << std::endl;
  std::cout << "
" << std::endl;

  // initiate result matrix
  std::map<std::string, std::map<std::string, std::pair<int, int>>> results;
  for (auto it0 = expressions.begin(); it0 != expressions.end(); ++it0) {
    results[it0 -> raw_expression] = std::map<std::string, std::pair<int, int>>();
    for (auto it1(it0); it1 != expressions.end(); ++it1) {
      results[it0 -> raw_expression][it1 -> raw_expression] = std::make_pair(0, 0);
    }
  }
  int total_programs_cnt = 0;
  int selected_programs_cnt = 0;

  // run through dates
  std::vector<std::string> missing_files;
  std::vector<std::string> corrupt_files;
  for (auto it = file_list.begin(); it != file_list.end(); ++it) {
    boost::gregorian::date::ymd_type ymd = current_date.year_month_day();
    std::cout << "Processing " << ymd.month << " "
              << ymd.day << ", " << ymd.year
              << "...
" << std::endl;
    if (snap::io::file_exists(*it)) {
      std::vector<snap::Program> programs;
      try {
        programs = snap::io::parse_programs(*it);
      } catch (snap::io::CorruptFileException &e) {
        programs.clear();
        current_date += boost::gregorian::date_duration(1);
        corrupt_files.push_back(*it);
        continue;
      }
      total_programs_cnt += programs.size();
      for (auto p = programs.begin(); p != programs.end(); ++p) {
        ++selected_programs_cnt;
        std::map<std::string, std::vector<int>> raw_match_positions = snap::find(patterns, p -> lower_text);
        std::map<std::string, std::vector<int>> match_positions = evaluate_expressions(expressions, raw_match_positions);
        std::map<std::string, std::map<std::string, int>> cooccurences = snap::pair(match_positions, distance);
        for (auto it0 = cooccurences.begin(); it0 != cooccurences.end(); ++it0) {
          for (auto it1 = (it0 -> second).begin(); it1 != (it0 -> second).end(); ++it1) {
            if (it1 -> second > 0) {
              ++results[it0 -> first][it1 -> first].first;
              results[it0 -> first][it1 -> first].second += it1 -> second;
            }
          }
        }
      }
    } else {
      missing_files.push_back(*it);
    }
    current_date += boost::gregorian::date_duration(1);
  }
  std::cout << "
";
  std::cout << "
" << std::endl;
  snap::web::print_missing_files(missing_files);
  std::cout << "
" << std::endl;
  snap::web::print_corrupt_files(corrupt_files);
  std::cout << "
" << std::endl;

  // print results
  std::cout << "
" << std::endl;
  std::cout << "Selected Programs Count: " << selected_programs_cnt << std::endl;
  std::cout << "Total Programs Count: " << total_programs_cnt << std::endl;
  std::cout << "search_string_1\tsearch_string_2\tmatching_programs_cnt\ttotal_matches_cnt" << std::endl;
  for (auto it0 = results.begin(); it0 != results.end(); ++it0) {
    for (auto it1 = (it0 -> second).begin(); it1 != (it0 -> second).end(); ++it1) {
      std::cout << it0 -> first << '\t' << it1 -> first << '\t'
                << (it1 -> second).first << '\t' << (it1 -> second).second << std::endl;
    }
  }

  std::cout << "\nMatching Programs\n" << std::endl;
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.first; },
                          std::cout, true, '\t');

  std::cout << "\nTotal Matches\n" << std::endl;
  snap::web::print_matrix(results,
                          [](std::pair<int, int> x) -> int { return x.second; },
                          std::cout, true, '\t');
  std::cout << "
" << std::endl;

  std::cout << "
Output Files
" << std::endl;
  srand(time(NULL));
  std::string random_id = std::to_string(rand());

  output_files(results, random_id, snap::date::date_to_string(from_date), "");
  remove_zero_keys(results);
  output_files(results, random_id, snap::date::date_to_string(from_date), "no zeroes");

  // output for visualization
  output_visualization(results, random_id, snap::date::date_to_string(from_date));

  double duration = (std::clock() - start_time) / (double) CLOCKS_PER_SEC;
  std::cout << "
Time taken (seconds): " << duration << "
" << std::endl;
  snap::web::close_html();
  return 0;
}
<|endoftext|>