<commit_before>//
// Copyright (C) 2011-15 DyND Developers
// BSD 2-Clause License, see LICENSE.txt
//

#include "gfunc_callable_functions.hpp"
#include "utility_functions.hpp"
#include "array_functions.hpp"
#include "array_as_py.hpp"
#include "array_assign_from_py.hpp"

#include <dynd/types/struct_type.hpp>
#include <dynd/types/builtin_type_properties.hpp>
#include <dynd/types/type_type.hpp>

using namespace std;
using namespace dynd;
using namespace pydynd;

PyTypeObject *pydynd::WTypeCallable_Type;

void pydynd::init_w__type_callable_typeobject(PyObject *type)
{
  WTypeCallable_Type = (PyTypeObject *)type;
}

void pydynd::add__type_names_to_dir_dict(const ndt::type &dt, PyObject *dict)
{
  if (!dt.is_builtin()) {
    // Add the type properties
    std::map<std::string, nd::callable> properties;
    dt.extended()->get_dynamic_type_properties(properties);
    for (const auto &pair : properties) {
      if (PyDict_SetItemString(dict, pair.first.c_str(), Py_None) < 0) {
        throw runtime_error("");
      }
    }
    // Add the type functions
    const std::pair<std::string, nd::callable> *functions;
    size_t count;
    dt.extended()->get_dynamic_type_functions(&functions, &count);
    for (size_t i = 0; i < count; ++i) {
      if (PyDict_SetItemString(dict, functions[i].first.c_str(), Py_None) < 0) {
        throw runtime_error("");
      }
    }
  }
}

PyObject *pydynd::get__type_dynamic_property(const dynd::ndt::type &dt,
                                             PyObject *name)
{
  if (!dt.is_builtin()) {
    // Search for a property
    std::map<std::string, nd::callable> properties;
    dt.extended()->get_dynamic_type_properties(properties);
    // TODO: We probably want to make some kind of acceleration structure for
    // the name lookup
    std::string nstr = pystring_as_string(name);
    nd::callable p = properties[nstr];
    if (!p.is_null()) {
      return DyND_PyWrapper_New(p(dt));
    }
    // Search for a function
    const std::pair<std::string, nd::callable> *functions;
    size_t count;
    dt.extended()->get_dynamic_type_functions(&functions, &count);
    if (count > 0) {
      std::string nstr = pystring_as_string(name);
      for (size_t i = 0; i < count; ++i) {
        if (functions[i].first == nstr) {
          return wrap__type_callable(nstr, functions[i].second, dt);
        }
      }
    }
  }

  PyErr_SetObject(PyExc_AttributeError, name);
  return NULL;
}

static void set_single_parameter(const std::string &funcname,
                                 const std::string &paramname,
                                 const ndt::type &paramtype, char *arrmeta,
                                 char *data, const ndt::type &value)
{
  if (paramtype.get_type_id() != type_type_id) {
    stringstream ss;
    ss << "parameter \"" << paramname << "\" of dynd callable \"" << funcname
       << "\" with type " << paramtype;
    ss << " cannot accept a dynd type as its value";
    throw runtime_error(ss.str());
  }
  // The type is encoded as either a raw type id, or a pointer to a base_type,
  // just as the gfunc object is expecting.
  ndt::type(value).swap(*reinterpret_cast<dynd::ndt::type *>(data));
}

static void set_single_parameter(const std::string &funcname,
                                 const std::string &paramname,
                                 const ndt::type &paramtype, char *arrmeta,
                                 char *data, const nd::array &value)
{
  // NOTE: ndarrayarg is a borrowed reference to an nd::array
  if (paramtype.get_type_id() != ndarrayarg_type_id) {
    stringstream ss;
    ss << "parameter \"" << paramname << "\" of dynd callable \"" << funcname
       << "\" with type " << paramtype;
    ss << " cannot accept an array as its value";
    throw runtime_error(ss.str());
  }
  *(const void **)data = value.get();
}

/**
 * This converts a single PyObject input parameter into the requested dynd
 * parameter data.
 *
 * \param out_storage  This is a hack because dynd doesn't support object
 * lifetime management
 */
static void set_single_parameter(const ndt::type &paramtype, char *arrmeta,
                                 char *data, PyObject *value,
                                 vector<nd::array> &out_storage)
{
  // NOTE: ndarrayarg is a borrowed reference to an nd::array
  if (paramtype.get_type_id() == ndarrayarg_type_id) {
    out_storage.push_back(
        array_from_py(value, 0, false, &eval::default_eval_context));
    *(const void **)data = out_storage.back().get();
  }
  else {
    array_no_dim_broadcast_assign_from_py(paramtype, arrmeta, data, value,
                                          &eval::default_eval_context);
  }
}

PyObject *pydynd::wrap__type_callable(const std::string &funcname,
                                      const dynd::nd::callable &c,
                                      const dynd::ndt::type &d)
{
  WTypeCallable *result =
      (WTypeCallable *)WTypeCallable_Type->tp_alloc(WTypeCallable_Type, 0);
  if (!result) {
    return NULL;
  }
  // Calling tp_alloc doesn't call Cython's __cinit__, so do the placement new
  // here

  new (&result->v) _type_callable_wrapper();
  result->v.d = d;
  result->v.c = c;
  result->v.funcname = funcname;
  return (PyObject *)result;
}

static PyObject *_type_callable_call(const std::string &funcname,
                                     const nd::callable &c, const ndt::type &d,
                                     PyObject *args, PyObject *kwargs)
{
  return NULL;

  // Convert kwds into nd::arrays
  intptr_t nkwd = PyDict_Size(kwargs);
  vector<std::string> kwd_names_strings(nkwd);
  std::vector<const char *> kwd_names(nkwd);
  std::vector<dynd::nd::array> kwd_values(nkwd);
  PyObject *key, *value;
  for (Py_ssize_t i = 0, j = 0; PyDict_Next(kwargs, &i, &key, &value); ++j) {
    kwd_names_strings[j] = pystring_as_string(key);
    kwd_names[j] = kwd_names_strings[j].c_str();
    kwd_values[j] =
        array_from_py(value, 0, false, &dynd::eval::default_eval_context);
  }

  kwd_names_strings.insert(kwd_names_strings.begin(), "self");
  kwd_names.insert(kwd_names.begin(), "self");
  kwd_values.insert(kwd_values.begin(), d);

  dynd::nd::array result = const_cast<nd::callable &>(c)(
      0, static_cast<nd::array *>(NULL),
      kwds(nkwd + 1, kwd_names.empty() ? NULL : kwd_names.data(),
           kwd_values.empty() ? NULL : kwd_values.data()));
  return DyND_PyWrapper_New(result);

  /*
    const ndt::type &pdt = c.get_parameters_type();
    vector<nd::array> storage;
    nd::array params = nd::empty(pdt);
    const ndt::struct_type *fsdt = pdt.extended<ndt::struct_type>();
    // Set the 'self' parameter value
    set_single_parameter(funcname, fsdt->get_field_name(0),
                         fsdt->get_field_type(0),
                         params.get()->metadata() + fsdt->get_arrmeta_offset(0),
                         params.get()->data +
                             fsdt->get_data_offsets(params.get()->metadata())[0],
                         d);

    fill_thiscall_parameters_array(funcname, c, args, kwargs, params, storage);

    return DyND_PyWrapper_New(c.call_generic(params));
  */

  return NULL;
}

PyObject *pydynd::_type_callable_call(const _type_callable_wrapper &dcw,
                                      PyObject *args, PyObject *kwargs)
{
  return _type_callable_call(dcw.funcname, dcw.c, dcw.d, args, kwargs);
}

PyObject *pydynd::call__type_constructor_function(const dynd::ndt::type &dt,
                                                  PyObject *args,
                                                  PyObject *kwargs)
{
  // First find the __construct__ callable
  if (!dt.is_builtin()) {
    const std::pair<std::string, nd::callable> *properties;
    size_t count;
    // Search for a function
    dt.extended()->get_dynamic_type_functions(&properties, &count);
    if (count > 0) {
      for (size_t i = 0; i < count; ++i) {
        return _type_callable_call("self", properties[i].second, dt, args,
                                   kwargs);
      }
    }
  }

  stringstream ss;
  ss << "dynd type " << dt << " has no array constructor function";
  PyErr_SetString(PyExc_TypeError, ss.str().c_str());
  return NULL;
}
<commit_msg>Update to match libdynd<commit_after>//
// Copyright (C) 2011-15 DyND Developers
// BSD 2-Clause License, see LICENSE.txt
//

#include "gfunc_callable_functions.hpp"
#include "utility_functions.hpp"
#include "array_functions.hpp"
#include "array_as_py.hpp"
#include "array_assign_from_py.hpp"

#include <dynd/types/struct_type.hpp>
#include <dynd/types/builtin_type_properties.hpp>
#include <dynd/types/type_type.hpp>

using namespace std;
using namespace dynd;
using namespace pydynd;

PyTypeObject *pydynd::WTypeCallable_Type;

void pydynd::init_w__type_callable_typeobject(PyObject *type)
{
  WTypeCallable_Type = (PyTypeObject *)type;
}

void pydynd::add__type_names_to_dir_dict(const ndt::type &dt, PyObject *dict)
{
  if (!dt.is_builtin()) {
    // Add the type properties
    std::map<std::string, nd::callable> properties;
    dt.extended()->get_dynamic_type_properties(properties);
    for (const auto &pair : properties) {
      if (PyDict_SetItemString(dict, pair.first.c_str(), Py_None) < 0) {
        throw runtime_error("");
      }
    }
    // Add the type functions
    std::map<std::string, nd::callable> functions;
    dt.extended()->get_dynamic_type_functions(functions);
    for (const auto &pair : functions) {
      if (PyDict_SetItemString(dict, pair.first.c_str(), Py_None) < 0) {
        throw runtime_error("");
      }
    }
  }
}

PyObject *pydynd::get__type_dynamic_property(const dynd::ndt::type &dt,
                                             PyObject *name)
{
  if (!dt.is_builtin()) {
    // Search for a property
    std::map<std::string, nd::callable> properties;
    dt.extended()->get_dynamic_type_properties(properties);
    // TODO: We probably want to make some kind of acceleration structure for
    // the name lookup
    std::string nstr = pystring_as_string(name);
    nd::callable p = properties[nstr];
    if (!p.is_null()) {
      return DyND_PyWrapper_New(p(dt));
    }
    // Search for a function
    std::map<std::string, nd::callable> functions;
    dt.extended()->get_dynamic_type_functions(functions);
    nd::callable f = functions[nstr];
    if (!f.is_null()) {
      return wrap__type_callable(nstr, f, dt);
    }
  }

  PyErr_SetObject(PyExc_AttributeError, name);
  return NULL;
}

static void set_single_parameter(const std::string &funcname,
                                 const std::string &paramname,
                                 const ndt::type &paramtype, char *arrmeta,
                                 char *data, const ndt::type &value)
{
  if (paramtype.get_type_id() != type_type_id) {
    stringstream ss;
    ss << "parameter \"" << paramname << "\" of dynd callable \"" << funcname
       << "\" with type " << paramtype;
    ss << " cannot accept a dynd type as its value";
    throw runtime_error(ss.str());
  }
  // The type is encoded as either a raw type id, or a pointer to a base_type,
  // just as the gfunc object is expecting.
  ndt::type(value).swap(*reinterpret_cast<dynd::ndt::type *>(data));
}

static void set_single_parameter(const std::string &funcname,
                                 const std::string &paramname,
                                 const ndt::type &paramtype, char *arrmeta,
                                 char *data, const nd::array &value)
{
  // NOTE: ndarrayarg is a borrowed reference to an nd::array
  if (paramtype.get_type_id() != ndarrayarg_type_id) {
    stringstream ss;
    ss << "parameter \"" << paramname << "\" of dynd callable \"" << funcname
       << "\" with type " << paramtype;
    ss << " cannot accept an array as its value";
    throw runtime_error(ss.str());
  }
  *(const void **)data = value.get();
}

/**
 * This converts a single PyObject input parameter into the requested dynd
 * parameter data.
 *
 * \param out_storage  This is a hack because dynd doesn't support object
 * lifetime management
 */
static void set_single_parameter(const ndt::type &paramtype, char *arrmeta,
                                 char *data, PyObject *value,
                                 vector<nd::array> &out_storage)
{
  // NOTE: ndarrayarg is a borrowed reference to an nd::array
  if (paramtype.get_type_id() == ndarrayarg_type_id) {
    out_storage.push_back(
        array_from_py(value, 0, false, &eval::default_eval_context));
    *(const void **)data = out_storage.back().get();
  }
  else {
    array_no_dim_broadcast_assign_from_py(paramtype, arrmeta, data, value,
                                          &eval::default_eval_context);
  }
}

PyObject *pydynd::wrap__type_callable(const std::string &funcname,
                                      const dynd::nd::callable &c,
                                      const dynd::ndt::type &d)
{
  WTypeCallable *result =
      (WTypeCallable *)WTypeCallable_Type->tp_alloc(WTypeCallable_Type, 0);
  if (!result) {
    return NULL;
  }
  // Calling tp_alloc doesn't call Cython's __cinit__, so do the placement new
  // here

  new (&result->v) _type_callable_wrapper();
  result->v.d = d;
  result->v.c = c;
  result->v.funcname = funcname;
  return (PyObject *)result;
}

static PyObject *_type_callable_call(const std::string &funcname,
                                     const nd::callable &c, const ndt::type &d,
                                     PyObject *args, PyObject *kwargs)
{
  return NULL;

  // Convert kwds into nd::arrays
  intptr_t nkwd = PyDict_Size(kwargs);
  vector<std::string> kwd_names_strings(nkwd);
  std::vector<const char *> kwd_names(nkwd);
  std::vector<dynd::nd::array> kwd_values(nkwd);
  PyObject *key, *value;
  for (Py_ssize_t i = 0, j = 0; PyDict_Next(kwargs, &i, &key, &value); ++j) {
    kwd_names_strings[j] = pystring_as_string(key);
    kwd_names[j] = kwd_names_strings[j].c_str();
    kwd_values[j] =
        array_from_py(value, 0, false, &dynd::eval::default_eval_context);
  }

  kwd_names_strings.insert(kwd_names_strings.begin(), "self");
  kwd_names.insert(kwd_names.begin(), "self");
  kwd_values.insert(kwd_values.begin(), d);

  dynd::nd::array result = const_cast<nd::callable &>(c)(
      0, static_cast<nd::array *>(NULL),
      kwds(nkwd + 1, kwd_names.empty() ? NULL : kwd_names.data(),
           kwd_values.empty() ? NULL : kwd_values.data()));
  return DyND_PyWrapper_New(result);

  /*
    const ndt::type &pdt = c.get_parameters_type();
    vector<nd::array> storage;
    nd::array params = nd::empty(pdt);
    const ndt::struct_type *fsdt = pdt.extended<ndt::struct_type>();
    // Set the 'self' parameter value
    set_single_parameter(funcname, fsdt->get_field_name(0),
                         fsdt->get_field_type(0),
                         params.get()->metadata() + fsdt->get_arrmeta_offset(0),
                         params.get()->data +
                             fsdt->get_data_offsets(params.get()->metadata())[0],
                         d);

    fill_thiscall_parameters_array(funcname, c, args, kwargs, params, storage);

    return DyND_PyWrapper_New(c.call_generic(params));
  */

  return NULL;
}

PyObject *pydynd::_type_callable_call(const _type_callable_wrapper &dcw,
                                      PyObject *args, PyObject *kwargs)
{
  return _type_callable_call(dcw.funcname, dcw.c, dcw.d, args, kwargs);
}

PyObject *pydynd::call__type_constructor_function(const dynd::ndt::type &dt,
                                                  PyObject *args,
                                                  PyObject *kwargs)
{
  // First find the __construct__ callable
  if (!dt.is_builtin()) {
    std::map<std::string, nd::callable> functions;
    // Search for a function
    dt.extended()->get_dynamic_type_functions(functions);
  }

  stringstream ss;
  ss << "dynd type " << dt << " has no array constructor function";
  PyErr_SetString(PyExc_TypeError, ss.str().c_str());
  return NULL;
}
<|endoftext|>


<commit_before>#include "include/apprunner.hpp"

namespace apprunner
{
	DECLARE_MODULE_INFORMATION_BEGIN
	DECLARE_MODULE_INFORMATION_NAME(AppRunner)
	DECLARE_MODULE_INFORMATION_VERSION(0)
	DECLARE_MODULE_INFORMATION_SUBVERSION(1)
	DECLARE_MODULE_INFORMATION_PATCH(2)
	DECLARE_MODULE_INFORMATION_END

	AppRunner::AppRunner()
	{
	}

	AppRunner::~AppRunner()
	{
	}
	moduler::ModuleInformation * const AppRunner::moduleInformation() const
	{
		return &moduleInfo;
	}

	bool AppRunner::start()
	{
		return true;
	}

	bool AppRunner::stop()
	{
		return true;
	}
}

using namespace apprunner;
DEFINE_MODULE_CREATION(AppRunner);
<commit_msg>Correct use of defines<commit_after>#include "include/apprunner.hpp"

namespace apprunner
{
	DECLARE_MODULE_INFORMATION_BEGIN
	DECLARE_MODULE_INFORMATION_NAME(AppRunner),
	DECLARE_MODULE_INFORMATION_VERSION(0),
	DECLARE_MODULE_INFORMATION_SUBVERSION(1),
	DECLARE_MODULE_INFORMATION_PATCH(3)
	DECLARE_MODULE_INFORMATION_END

	AppRunner::AppRunner()
	{
	}

	AppRunner::~AppRunner()
	{
	}
	moduler::ModuleInformation * const AppRunner::moduleInformation() const
	{
		return &moduleInfo;
	}

	bool AppRunner::start()
	{
		return true;
	}

	bool AppRunner::stop()
	{
		return true;
	}
}

using namespace apprunner;
DEFINE_MODULE_CREATION(AppRunner);
<|endoftext|>


<commit_before>/* Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for derived genetic algorithm class
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#include <numeric>

#include "genetic_algorithm.hpp"
#include "random_generator.hpp"

void Genetic::gaussian_mutate(Individual & mutant, int_dist & percent) const {
  // GA mutation sequence using a normal distribution
  normal_dist delta_dist(mean, stddev); // unit Gaussian distribution for delta
  for (parameter & gene : mutant)
    // short circuit for problem.chance == 1
    if (problem.chance || percent(rg.engine) < int(100 * problem.chance))
      mutant.mutate(gene, gene * delta_dist(rg.engine));
}

void Genetic::jumping_mutate(Individual & mutant, int_dist & percent) const {
  // jumping sequence like snewt's
  real_dist delta_dist(problem.domain_min, problem.domain_max);
  for (parameter & gene : mutant)
    if (percent(rg.engine) < int(100 * jumping_mutation_rate))
      mutant.mutate(gene, delta_dist(rg.engine));
}

const Individual Genetic::mutate(const Individual & subject) const {
  Individual mutant = subject; // non-const copy to mutate
  int_dist percent(0, 100);
  switch(mutation_type) {
  case 'g':
    gaussian_mutate(mutant, percent);
    break;
  case 'j':
    jumping_mutate(mutant, percent);
    break;
  }
  // update fitness
  mutant.fitness = problem.fitness(mutant);
  return mutant;
}

const Genetic::population Genetic::selection(const Genetic::population & generation) const {
  // implements tournament selection, returning desired number of best parents
  population parents;
  int_dist population_dist(0, population_size - 1); // closed interval, so (-1)
  for (int i = 0; i < crossover_size; ++i) {
    population contestants;
    // create tournament of random members drawn from generation
    for (int i = 0; i < tournament_size; ++i)
      contestants.emplace_back(generation[population_dist(rg.engine)]);
    // select best member from each tournament
    parents.emplace_back(*std::max_element(contestants.begin(), contestants.end()));
  }
  // return best Individual from a set of contestants
  return parents;
}

void Genetic::uniform_crossover(Genetic::population & children, int_dist & percent) const {
  // uniform crossover
  for (unsigned long i = 0; i < children[0].size(); ++i)
    if (percent(rg.engine) < int(100 * 0.5))
      std::swap(children[0][i], children[1][i]);
}

void Genetic::arithmetic_crossover(Genetic::population & children, int_dist & percent) const {
  // arithmetic crossover
  const population mates = children;
  real_dist alpha_dist(-0.1, 1.1);
  for (unsigned long i = 0; i < children[0].size(); ++i) {
    parameter alpha = alpha_dist(rg.engine);
    // recombine each child with crossover_chance probability
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance))
      children[0][i] = alpha * mates[0][i] + (1 - alpha) * mates[1][i];
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance))
      children[1][i] = (1 - alpha) * mates[0][i] + alpha * mates[1][i];
  }
}

void Genetic::two_point_crossover(Genetic::population & children, int_dist & percent) const {
    // two-point crossover
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance)) {
      int_dist gene_dist(0, children[0].size() - 1);
      int start = gene_dist(rg.engine);
      int length = gene_dist(rg.engine);
      for (Individual & child : children)
	std::rotate(child.begin(), child.begin() + start, child.end());
      for (int i = 0; i < length; i++)
	std::swap(children[0][i], children[1][i]);
    }
}

const Genetic::population Genetic::crossover(const Genetic::population & mates) const {
  population children = mates;
  int_dist percent(0, 100);
  switch(crossover_type) {
  case 'u':
    uniform_crossover(children, percent);
    break;
  case 'a':
    arithmetic_crossover(children, percent);
    break;
  case 't':
    two_point_crossover(children, percent);
    break;
  }
  // update fitnesses
  for (Individual & child : children) child.fitness = problem.fitness(child);
  return children;
}

const Individual Genetic::solve() const {
  // setup basic logging
  std::ofstream log("logs/" + problem.name + ".dat");
  log << "# Solving the " << problem.represent()
      << "# Using a Genetic Algorithm"
      << " with population size " << population_size
      << ", tournament size " << tournament_size
      << ", crossover size " << crossover_size
      << ", crossover chance of " << crossover_chance
      << ", mutation chance of " << jumping_mutation_rate
      << ", and elitism replacement size " << elitism << "." << std::endl;
  while(true) {
    // create initial population
    population generation;
    Individual best;
    int_dist population_dist(0, population_size - 1); // closed interval, so (-1)
    for (int i = 0; i < population_size; ++i)
      generation.emplace_back(problem.potential());
    // generations loop
    for (long i = 0; i < problem.iterations; ++i) {
      // find generation's best member
      best = *std::max_element(generation.begin(), generation.end());
      parameter sum = std::accumulate(generation.begin(), generation.end(), 0.);
      // logging
      log << i << '\t' << best.fitness << '\t' << sum / population_size << '\n';
      // terminating condition
      if (best > problem.goal) return best;
      // selection and mutation stage
      population offspring;
      while(offspring.size() != population_size) {
	// tournament selection of parents
	const population parents = selection(generation);
	// crossover
	const population children = crossover(parents);
	// add mutated children to offspring
	for (const Individual child : children) offspring.emplace_back(mutate(child));
      }
      // replace generation with offspring
      generation.swap(offspring);
      // elitism replacement of random individuals
      for (int i = 0; i < elitism; ++i)
	generation[population_dist(rg.engine)] = best;
    }
    log.close();
    return best;
  }
}
<commit_msg>Fixing arithmetic crossover (using two alphas)<commit_after>/* Copyright 2014 Andrew Schwartzmeyer
 *
 * Source file for derived genetic algorithm class
 */

#include <algorithm>
#include <fstream>
#include <iostream>
#include <numeric>

#include "genetic_algorithm.hpp"
#include "random_generator.hpp"

void Genetic::gaussian_mutate(Individual & mutant, int_dist & percent) const {
  // GA mutation sequence using a normal distribution
  normal_dist delta_dist(mean, stddev); // unit Gaussian distribution for delta
  for (parameter & gene : mutant)
    // short circuit for problem.chance == 1
    if (problem.chance || percent(rg.engine) < int(100 * problem.chance))
      mutant.mutate(gene, gene * delta_dist(rg.engine));
}

void Genetic::jumping_mutate(Individual & mutant, int_dist & percent) const {
  // jumping sequence like snewt's
  real_dist delta_dist(problem.domain_min, problem.domain_max);
  for (parameter & gene : mutant)
    if (percent(rg.engine) < int(100 * jumping_mutation_rate))
      mutant.mutate(gene, delta_dist(rg.engine));
}

const Individual Genetic::mutate(const Individual & subject) const {
  Individual mutant = subject; // non-const copy to mutate
  int_dist percent(0, 100);
  switch(mutation_type) {
  case 'g':
    gaussian_mutate(mutant, percent);
    break;
  case 'j':
    jumping_mutate(mutant, percent);
    break;
  }
  // update fitness
  mutant.fitness = problem.fitness(mutant);
  return mutant;
}

const Genetic::population Genetic::selection(const Genetic::population & generation) const {
  // implements tournament selection, returning desired number of best parents
  population parents;
  int_dist population_dist(0, population_size - 1); // closed interval, so (-1)
  for (int i = 0; i < crossover_size; ++i) {
    population contestants;
    // create tournament of random members drawn from generation
    for (int i = 0; i < tournament_size; ++i)
      contestants.emplace_back(generation[population_dist(rg.engine)]);
    // select best member from each tournament
    parents.emplace_back(*std::max_element(contestants.begin(), contestants.end()));
  }
  // return best Individual from a set of contestants
  return parents;
}

void Genetic::uniform_crossover(Genetic::population & children, int_dist & percent) const {
  // uniform crossover
  for (unsigned long i = 0; i < children[0].size(); ++i)
    if (percent(rg.engine) < int(100 * 0.5))
      std::swap(children[0][i], children[1][i]);
}

void Genetic::arithmetic_crossover(Genetic::population & children, int_dist & percent) const {
  // arithmetic crossover
  const population mates = children;
  real_dist alpha_dist(-0.1, 1.1);
  for (unsigned long i = 0; i < children[0].size(); ++i) {
    parameter alpha_1 = alpha_dist(rg.engine);
    parameter alpha_2 = alpha_dist(rg.engine);
    // recombine each child with crossover_chance probability
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance))
      children[0][i] = alpha_1 * mates[0][i] + (1 - alpha_1) * mates[1][i];
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance))
      children[1][i] = (1 - alpha_2) * mates[0][i] + alpha_2 * mates[1][i];
  }
}

void Genetic::two_point_crossover(Genetic::population & children, int_dist & percent) const {
    // two-point crossover
    if (crossover_chance || percent(rg.engine) < int(100 * crossover_chance)) {
      int_dist gene_dist(0, children[0].size() - 1);
      int start = gene_dist(rg.engine);
      int length = gene_dist(rg.engine);
      for (Individual & child : children)
	std::rotate(child.begin(), child.begin() + start, child.end());
      for (int i = 0; i < length; i++)
	std::swap(children[0][i], children[1][i]);
    }
}

const Genetic::population Genetic::crossover(const Genetic::population & mates) const {
  population children = mates;
  int_dist percent(0, 100);
  switch(crossover_type) {
  case 'u':
    uniform_crossover(children, percent);
    break;
  case 'a':
    arithmetic_crossover(children, percent);
    break;
  case 't':
    two_point_crossover(children, percent);
    break;
  }
  // update fitnesses
  for (Individual & child : children) child.fitness = problem.fitness(child);
  return children;
}

const Individual Genetic::solve() const {
  // setup basic logging
  std::ofstream log("logs/" + problem.name + ".dat");
  log << "# Solving the " << problem.represent()
      << "# Using a Genetic Algorithm"
      << " with population size " << population_size
      << ", tournament size " << tournament_size
      << ", crossover size " << crossover_size
      << ", crossover chance of " << crossover_chance
      << ", mutation chance of " << jumping_mutation_rate
      << ", and elitism replacement size " << elitism << "." << std::endl;
  while(true) {
    // create initial population
    population generation;
    Individual best;
    int_dist population_dist(0, population_size - 1); // closed interval, so (-1)
    for (int i = 0; i < population_size; ++i)
      generation.emplace_back(problem.potential());
    // generations loop
    for (long i = 0; i < problem.iterations; ++i) {
      // find generation's best member
      best = *std::max_element(generation.begin(), generation.end());
      parameter sum = std::accumulate(generation.begin(), generation.end(), 0.);
      // logging
      log << i << '\t' << best.fitness << '\t' << sum / population_size << '\n';
      // terminating condition
      if (best > problem.goal) return best;
      // selection and mutation stage
      population offspring;
      while(offspring.size() != population_size) {
	// tournament selection of parents
	const population parents = selection(generation);
	// crossover
	const population children = crossover(parents);
	// add mutated children to offspring
	for (const Individual child : children) offspring.emplace_back(mutate(child));
      }
      // replace generation with offspring
      generation.swap(offspring);
      // elitism replacement of random individuals
      for (int i = 0; i < elitism; ++i)
	generation[population_dist(rg.engine)] = best;
    }
    log.close();
    return best;
  }
}
<|endoftext|>


<commit_before><commit_msg>fix bugs when merging<commit_after><|endoftext|>


<commit_before>//
// TreeView.cpp
//
// Copyright (c) 2001-2008 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtdata/FilePath.h"
#include "vtdata/vtLog.h"

#include "App.h"
#include "TreeView.h"
#include "MenuEnum.h"	// for LayerTree_Ctrl
#include "Frame.h"
#include "BuilderView.h"
#include "vtui/Helper.h"

DECLARE_APP(BuilderApp)

// Under Windows, the icons are in the .rc file; on Unix, they are included
// from .xpm files.
#ifndef __WXMSW__
#include "building.xpm"
#include "file1.xpm"
#include "file2.xpm"
#include "folder1.xpm"
#include "folder2.xpm"
#include "folder3.xpm"

#include "grid.xpm"
#include "image.xpm"
#include "raw.xpm"
#include "road.xpm"
#include "veg1.xpm"
#include "water.xpm"
#include "util.xpm"
#include "transit.xpm"
#endif

/////////////////////////////////////////////////

// MyTreeCtrl implementation
IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)

MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
	const wxPoint& pos, const wxSize& size,
	long style)
: wxTreeCtrl(parent, id, pos, size, style)
{
	m_reverseSort = false;
	m_imageListNormal = NULL;
	m_bShowPaths = true;
	m_bUser = true;

	CreateImageList(16);

	// Add some items to the tree
	RefreshTreeItems(NULL);
}

void MyTreeCtrl::CreateImageList(int size)
{
	delete m_imageListNormal;

	if ( size == -1 )
	{
		m_imageListNormal = NULL;
		return;
	}

	// Make an image list containing small icons
	m_imageListNormal = new wxImageList(size, size, TRUE);

	// should correspond to TreeCtrlIcon_xxx enum
	wxIcon icons[14];
	icons[0] = wxICON(file1);
	icons[1] = wxICON(file2);
	icons[2] = wxICON(folder1);
	icons[3] = wxICON(folder2);
	icons[4] = wxICON(folder3);
	icons[5] = wxICON(building);
	icons[6] = wxICON(road);
	icons[7] = wxICON(grid);
	icons[8] = wxICON(image);
	icons[9] = wxICON(veg1);
	icons[10] = wxICON(water);
	icons[11] = wxICON(transit);
	icons[12] = wxICON(util);
	icons[13] = wxICON(raw);

	int sizeOrig = icons[0].GetWidth();
	for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
	{
		if ( size == sizeOrig )
			m_imageListNormal->Add(icons[i]);
		else
			m_imageListNormal->Add(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size));
	}

	SetImageList(m_imageListNormal);
}

MyTreeCtrl::~MyTreeCtrl()
{
	delete m_imageListNormal;
}

int MyTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
	const wxTreeItemId& item2)
{
	if ( m_reverseSort )
	{
		// just exchange 1st and 2nd items
		return wxTreeCtrl::OnCompareItems(item2, item1);
	}
	else
	{
		return wxTreeCtrl::OnCompareItems(item1, item2);
	}
}

wxTreeItemId rootId;

wxTreeItemId MyTreeCtrl::AddRootItem(int image, const wxString &text)
{
	wxTreeItemId id = AppendItem(rootId, text, image);
	SetItemBold(id);
	return id;
}

wxString MyTreeCtrl::MakeItemName(vtLayerPtr lp)
{
	wxString str;
	if (lp->GetModified())
		str = _T("(*) ");
	wxString path = lp->GetLayerFilename();

	if (!m_bShowPaths)
		path = StartOfFilename(path);

	str += path;
	return str;
}

void MyTreeCtrl::RefreshTreeItems(MainFrame *pFrame)
{
	VTLOG("Refreshing Tree Items\n");

	// Deleting the previous items can call OnSelChanged, which can cause VTB
	//  to forget the active layer, so indicate that this is not user input.
	m_bUser = false;
	DeleteAllItems();
	m_bUser = true;

	rootId = AddRoot(_("Layers"));
	SetItemBold(rootId);

	int	image, imageSel;

	wxTreeItemId elevId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Grid, _("Elevation"));
	SetItemData(elevId, new MyTreeItemData(LT_ELEVATION));

	wxTreeItemId imageId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Image, _("Images"));
	SetItemData(imageId, new MyTreeItemData(LT_IMAGE));

	wxTreeItemId buildId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Building, _("Structures"));
	SetItemData(buildId, new MyTreeItemData(LT_STRUCTURE));

	wxTreeItemId roadId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Road, _("Roads"));
	SetItemData(roadId, new MyTreeItemData(LT_ROAD));

	wxTreeItemId vegId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Veg1, _("Vegetation"));
	SetItemData(vegId, new MyTreeItemData(LT_VEG));

	wxTreeItemId waterId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Water, _("Water"));
	SetItemData(waterId, new MyTreeItemData(LT_WATER));

#if SUPPORT_TRANSIT
	wxTreeItemId transId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Transit, _("Transit"));
	SetItemData(transId, new MyTreeItemData(LT_TRANSIT));
#endif

	wxTreeItemId utilityId = AddRootItem(MyTreeCtrl::TreeCtrlIcon_Utility, _("Utilities"));
	SetItemData(utilityId, new MyTreeItemData(LT_UTILITY));

	wxTreeItemId rawId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Raw, _("Raw"));
	SetItemData(rawId, new MyTreeItemData(LT_RAW));

	image = TreeCtrlIcon_File;
	imageSel = TreeCtrlIcon_FileSelected;
	vtLayerPtr lp;
	int iLayers = 0;
	if (pFrame) iLayers = pFrame->NumLayers();
	for (int i = 0; i < iLayers; i++)
	{
		lp = pFrame->GetLayer(i);

		wxString str = MakeItemName(lp);

		wxTreeItemId hItem;
		switch (lp->GetType())
		{
			case LT_ELEVATION:
				hItem = AppendItem(elevId, str, image, imageSel);
				break;
			case LT_IMAGE:
				hItem = AppendItem(imageId, str, image, imageSel);
				break;
			case LT_ROAD:
				hItem = AppendItem(roadId, str, image, imageSel);
				break;
			case LT_STRUCTURE:
				hItem = AppendItem(buildId, str, image, imageSel);
				break;
			case LT_VEG:
				hItem = AppendItem(vegId, str, image, imageSel);
				break;
			case LT_WATER:
				hItem = AppendItem(waterId, str, image, imageSel);
				break;
#if SUPPORT_TRANSIT
			case LT_TRANSIT:
				hItem = AppendItem(transId, str, image, imageSel);
				break;
#endif
			case LT_UTILITY:
				hItem = AppendItem(utilityId, str, image, imageSel);
				break;
			case LT_RAW:
				hItem = AppendItem(rawId, str, image, imageSel);
				break;
		}
		if (hItem.IsOk())
		{
			SetItemData(hItem, new MyTreeItemData(lp));

			if (lp == pFrame->GetActiveLayer())
				SelectItem(hItem);
		}
	}

	Expand(elevId);
	Expand(imageId);
	Expand(roadId);
	Expand(buildId);
	Expand(vegId);
	Expand(waterId);
#if SUPPORT_TRANSIT
	Expand(transId);
#endif
	Expand(utilityId);
	Expand(rawId);
}

void MyTreeCtrl::RefreshTreeStatus(MainFrame *pFrame)
{
	VTLOG("(Refreshing Tree Status)\n");

	wxTreeItemId root = GetRootItem();
	wxTreeItemId parent, item;

	wxTreeItemIdValue cookie;
	for (parent = GetFirstChild(root, cookie); parent; parent = GetNextChild(root, cookie))
	{
		wxTreeItemIdValue cookie2;
		for (item = GetFirstChild(parent, cookie2); item; item = GetNextChild(parent, cookie2))
		{
			MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
			if (data)
			{
				SetItemText(item, MakeItemName(data->m_pLayer));
				if (data->m_pLayer == pFrame->GetActiveLayer())
					SelectItem(item);
			}
		}
	}
}

// avoid repetition
#define TREE_EVENT_HANDLER(name)			\
void MyTreeCtrl::name(wxTreeEvent& event)	\
{											\
	event.Skip();							\
}

TREE_EVENT_HANDLER(OnBeginRDrag)
TREE_EVENT_HANDLER(OnDeleteItem)
TREE_EVENT_HANDLER(OnGetInfo)
TREE_EVENT_HANDLER(OnItemExpanded)
TREE_EVENT_HANDLER(OnItemExpanding)
TREE_EVENT_HANDLER(OnItemCollapsed)
TREE_EVENT_HANDLER(OnSelChanging)
TREE_EVENT_HANDLER(OnTreeKeyDown)

#undef TREE_EVENT_HANDLER

void MyTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	if (!m_bUser)	// only listen for actual user input
		return;

	wxTreeItemId item = event.GetItem();
	if (!item.IsOk())
		return;

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
	vtLayerPtr lp = NULL;
	if (data)
		lp = data->m_pLayer;

	MainFrame *frame = GetMainFrame();
	vtLayerPtr last = frame->GetActiveLayer();
	if (lp != last)
		frame->GetView()->SetActiveLayer(lp);

	LayerType curr_ltype = lp ? lp->GetType() : LT_UNKNOWN;
	LayerType last_ltype = last ? last->GetType() : LT_UNKNOWN;
	if (curr_ltype != last_ltype)
		frame->RefreshToolbars();
}

void MyTreeCtrl::OnItemRightClick(wxTreeEvent& event)
{
	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(itemId);
	if (data)
	{
		if (data->m_pLayer)
			m_clicked_layer_type = data->m_pLayer->GetType();
		else
			m_clicked_layer_type = data->m_type;

		wxMenu *popmenu = new wxMenu;
		if (data->m_pLayer)
		{
			popmenu->Append(ID_POPUP_TO_TOP, _("Move to Top (draw first)"));
			popmenu->Append(ID_POPUP_TO_BOTTOM, _("Move to Bottom (draw last)"));
			popmenu->AppendSeparator();
		}
		popmenu->Append(ID_POPUP_SHOWALL, _("Show All"));
		popmenu->Append(ID_POPUP_HIDEALL, _("Hide All"));
		PopupMenu(popmenu);
		delete popmenu;
	}
}

void MyTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnBeginLabelEdit");

	// for testing, prevent this items label editing
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't edit this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnEndLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnEndLabelEdit");

	// don't allow anything except letters in the labels
	if ( !event.GetLabel().IsWord() )
	{
		wxMessageBox("The label should contain only letters.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemCollapsing(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnItemCollapsing");

	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't collapse this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
#if 0
	// show some info about this item
	wxTreeItemId itemId = event.GetItem();
	MyTreeItemData *item = (MyTreeItemData *)GetItemData(itemId);

	if ( item != NULL )
	{
		item->ShowInfo(this);
	}
	wxLogMessage("OnItemActivated");
#endif
}

void MyTreeCtrl::OnRMouseDClick(wxMouseEvent& event)
{
#if 0
	wxTreeItemId id = HitTest(event.GetPosition());
	if ( !id )
		wxLogMessage("No item under mouse");
	else
	{
		MyTreeItemData *item = (MyTreeItemData *)GetItemData(id);
		if ( item )
			wxLogMessage("Item '%s' under mouse", item->GetDesc());
	}
#endif
}

/////////////////////////////////////////////////

BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
EVT_TREE_BEGIN_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginDrag)
EVT_TREE_BEGIN_RDRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginRDrag)
EVT_TREE_END_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnEndDrag)
EVT_TREE_BEGIN_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnBeginLabelEdit)
EVT_TREE_END_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnEndLabelEdit)
EVT_TREE_DELETE_ITEM(LayerTree_Ctrl, MyTreeCtrl::OnDeleteItem)
EVT_TREE_ITEM_EXPANDED(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanded)
EVT_TREE_ITEM_EXPANDING(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanding)
EVT_TREE_ITEM_COLLAPSED(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsed)
EVT_TREE_ITEM_COLLAPSING(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsing)
EVT_TREE_ITEM_RIGHT_CLICK(LayerTree_Ctrl, MyTreeCtrl::OnItemRightClick)
EVT_TREE_SEL_CHANGED(LayerTree_Ctrl, MyTreeCtrl::OnSelChanged)
EVT_TREE_SEL_CHANGING(LayerTree_Ctrl, MyTreeCtrl::OnSelChanging)
EVT_TREE_KEY_DOWN(LayerTree_Ctrl, MyTreeCtrl::OnTreeKeyDown)
EVT_TREE_ITEM_ACTIVATED(LayerTree_Ctrl, MyTreeCtrl::OnItemActivated)
EVT_RIGHT_DCLICK(MyTreeCtrl::OnRMouseDClick)
END_EVENT_TABLE()

<commit_msg>changed layer view refreshing to make it more likely the active layer stays visible, for a better user experience<commit_after>//
// TreeView.cpp
//
// Copyright (c) 2001-2008 Virtual Terrain Project
// Free for all uses, see license.txt for details.
//

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

#include "vtdata/FilePath.h"
#include "vtdata/vtLog.h"

#include "App.h"
#include "TreeView.h"
#include "MenuEnum.h"	// for LayerTree_Ctrl
#include "Frame.h"
#include "BuilderView.h"
#include "vtui/Helper.h"

DECLARE_APP(BuilderApp)

// Under Windows, the icons are in the .rc file; on Unix, they are included
// from .xpm files.
#ifndef __WXMSW__
#include "building.xpm"
#include "file1.xpm"
#include "file2.xpm"
#include "folder1.xpm"
#include "folder2.xpm"
#include "folder3.xpm"

#include "grid.xpm"
#include "image.xpm"
#include "raw.xpm"
#include "road.xpm"
#include "veg1.xpm"
#include "water.xpm"
#include "util.xpm"
#include "transit.xpm"
#endif

/////////////////////////////////////////////////

// MyTreeCtrl implementation
IMPLEMENT_DYNAMIC_CLASS(MyTreeCtrl, wxTreeCtrl)

MyTreeCtrl::MyTreeCtrl(wxWindow *parent, const wxWindowID id,
	const wxPoint& pos, const wxSize& size,
	long style)
: wxTreeCtrl(parent, id, pos, size, style)
{
	m_reverseSort = false;
	m_imageListNormal = NULL;
	m_bShowPaths = true;
	m_bUser = true;

	CreateImageList(16);

	// Add some items to the tree
	RefreshTreeItems(NULL);
}

void MyTreeCtrl::CreateImageList(int size)
{
	delete m_imageListNormal;

	if ( size == -1 )
	{
		m_imageListNormal = NULL;
		return;
	}

	// Make an image list containing small icons
	m_imageListNormal = new wxImageList(size, size, TRUE);

	// should correspond to TreeCtrlIcon_xxx enum
	wxIcon icons[14];
	icons[0] = wxICON(file1);
	icons[1] = wxICON(file2);
	icons[2] = wxICON(folder1);
	icons[3] = wxICON(folder2);
	icons[4] = wxICON(folder3);
	icons[5] = wxICON(building);
	icons[6] = wxICON(road);
	icons[7] = wxICON(grid);
	icons[8] = wxICON(image);
	icons[9] = wxICON(veg1);
	icons[10] = wxICON(water);
	icons[11] = wxICON(transit);
	icons[12] = wxICON(util);
	icons[13] = wxICON(raw);

	int sizeOrig = icons[0].GetWidth();
	for ( size_t i = 0; i < WXSIZEOF(icons); i++ )
	{
		if ( size == sizeOrig )
			m_imageListNormal->Add(icons[i]);
		else
			m_imageListNormal->Add(wxBitmap(icons[i]).ConvertToImage().Rescale(size, size));
	}

	SetImageList(m_imageListNormal);
}

MyTreeCtrl::~MyTreeCtrl()
{
	delete m_imageListNormal;
}

int MyTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
	const wxTreeItemId& item2)
{
	if ( m_reverseSort )
	{
		// just exchange 1st and 2nd items
		return wxTreeCtrl::OnCompareItems(item2, item1);
	}
	else
	{
		return wxTreeCtrl::OnCompareItems(item1, item2);
	}
}

wxTreeItemId rootId;

wxTreeItemId MyTreeCtrl::AddRootItem(int image, const wxString &text)
{
	wxTreeItemId id = AppendItem(rootId, text, image);
	SetItemBold(id);
	return id;
}

wxString MyTreeCtrl::MakeItemName(vtLayerPtr lp)
{
	wxString str;
	if (lp->GetModified())
		str = _T("(*) ");
	wxString path = lp->GetLayerFilename();

	if (!m_bShowPaths)
		path = StartOfFilename(path);

	str += path;
	return str;
}

void MyTreeCtrl::RefreshTreeItems(MainFrame *pFrame)
{
	VTLOG("Refreshing Tree Items\n");

	// Deleting the previous items can call OnSelChanged, which can cause VTB
	//  to forget the active layer, so indicate that this is not user input.
	m_bUser = false;
	DeleteAllItems();
	m_bUser = true;

	rootId = AddRoot(_("Layers"));
	SetItemBold(rootId);

	int	image, imageSel;

	wxTreeItemId elevId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Grid, _("Elevation"));
	SetItemData(elevId, new MyTreeItemData(LT_ELEVATION));

	wxTreeItemId imageId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Image, _("Images"));
	SetItemData(imageId, new MyTreeItemData(LT_IMAGE));

	wxTreeItemId buildId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Building, _("Structures"));
	SetItemData(buildId, new MyTreeItemData(LT_STRUCTURE));

	wxTreeItemId roadId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Road, _("Roads"));
	SetItemData(roadId, new MyTreeItemData(LT_ROAD));

	wxTreeItemId vegId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Veg1, _("Vegetation"));
	SetItemData(vegId, new MyTreeItemData(LT_VEG));

	wxTreeItemId waterId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Water, _("Water"));
	SetItemData(waterId, new MyTreeItemData(LT_WATER));

#if SUPPORT_TRANSIT
	wxTreeItemId transId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Transit, _("Transit"));
	SetItemData(transId, new MyTreeItemData(LT_TRANSIT));
#endif

	wxTreeItemId utilityId = AddRootItem(MyTreeCtrl::TreeCtrlIcon_Utility, _("Utilities"));
	SetItemData(utilityId, new MyTreeItemData(LT_UTILITY));

	wxTreeItemId rawId =	AddRootItem(MyTreeCtrl::TreeCtrlIcon_Raw, _("Raw"));
	SetItemData(rawId, new MyTreeItemData(LT_RAW));

	// Expand the groups here, before we add items to them, so that the active
	//  layer can be selected and kept in view, for a better user experience.
	Expand(elevId);
	Expand(imageId);
	Expand(roadId);
	Expand(buildId);
	Expand(vegId);
	Expand(waterId);
#if SUPPORT_TRANSIT
	Expand(transId);
#endif
	Expand(utilityId);
	Expand(rawId);

	image = TreeCtrlIcon_File;
	imageSel = TreeCtrlIcon_FileSelected;
	vtLayerPtr lp;
	int iLayers = 0;
	if (pFrame) iLayers = pFrame->NumLayers();
	for (int i = 0; i < iLayers; i++)
	{
		lp = pFrame->GetLayer(i);

		wxString str = MakeItemName(lp);

		wxTreeItemId hItem;
		switch (lp->GetType())
		{
			case LT_ELEVATION:
				hItem = AppendItem(elevId, str, image, imageSel);
				break;
			case LT_IMAGE:
				hItem = AppendItem(imageId, str, image, imageSel);
				break;
			case LT_ROAD:
				hItem = AppendItem(roadId, str, image, imageSel);
				break;
			case LT_STRUCTURE:
				hItem = AppendItem(buildId, str, image, imageSel);
				break;
			case LT_VEG:
				hItem = AppendItem(vegId, str, image, imageSel);
				break;
			case LT_WATER:
				hItem = AppendItem(waterId, str, image, imageSel);
				break;
#if SUPPORT_TRANSIT
			case LT_TRANSIT:
				hItem = AppendItem(transId, str, image, imageSel);
				break;
#endif
			case LT_UTILITY:
				hItem = AppendItem(utilityId, str, image, imageSel);
				break;
			case LT_RAW:
				hItem = AppendItem(rawId, str, image, imageSel);
				break;
		}
		if (hItem.IsOk())
		{
			SetItemData(hItem, new MyTreeItemData(lp));

			if (lp == pFrame->GetActiveLayer())
				SelectItem(hItem);
		}
	}

}

void MyTreeCtrl::RefreshTreeStatus(MainFrame *pFrame)
{
	VTLOG("(Refreshing Tree Status)\n");

	wxTreeItemId root = GetRootItem();
	wxTreeItemId parent, item;

	wxTreeItemIdValue cookie;
	for (parent = GetFirstChild(root, cookie); parent; parent = GetNextChild(root, cookie))
	{
		wxTreeItemIdValue cookie2;
		for (item = GetFirstChild(parent, cookie2); item; item = GetNextChild(parent, cookie2))
		{
			MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
			if (data)
			{
				SetItemText(item, MakeItemName(data->m_pLayer));
				if (data->m_pLayer == pFrame->GetActiveLayer())
					SelectItem(item);
			}
		}
	}
}

// avoid repetition
#define TREE_EVENT_HANDLER(name)			\
void MyTreeCtrl::name(wxTreeEvent& event)	\
{											\
	event.Skip();							\
}

TREE_EVENT_HANDLER(OnBeginRDrag)
TREE_EVENT_HANDLER(OnDeleteItem)
TREE_EVENT_HANDLER(OnGetInfo)
TREE_EVENT_HANDLER(OnItemExpanded)
TREE_EVENT_HANDLER(OnItemExpanding)
TREE_EVENT_HANDLER(OnItemCollapsed)
TREE_EVENT_HANDLER(OnSelChanging)
TREE_EVENT_HANDLER(OnTreeKeyDown)

#undef TREE_EVENT_HANDLER

void MyTreeCtrl::OnSelChanged(wxTreeEvent& event)
{
	if (!m_bUser)	// only listen for actual user input
		return;

	wxTreeItemId item = event.GetItem();
	if (!item.IsOk())
		return;

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(item);
	vtLayerPtr lp = NULL;
	if (data)
		lp = data->m_pLayer;

	MainFrame *frame = GetMainFrame();
	vtLayerPtr last = frame->GetActiveLayer();
	if (lp != last)
		frame->GetView()->SetActiveLayer(lp);

	LayerType curr_ltype = lp ? lp->GetType() : LT_UNKNOWN;
	LayerType last_ltype = last ? last->GetType() : LT_UNKNOWN;
	if (curr_ltype != last_ltype)
		frame->RefreshToolbars();
}

void MyTreeCtrl::OnItemRightClick(wxTreeEvent& event)
{
	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();

	MyTreeItemData *data = (MyTreeItemData *)GetItemData(itemId);
	if (data)
	{
		if (data->m_pLayer)
			m_clicked_layer_type = data->m_pLayer->GetType();
		else
			m_clicked_layer_type = data->m_type;

		wxMenu *popmenu = new wxMenu;
		if (data->m_pLayer)
		{
			popmenu->Append(ID_POPUP_TO_TOP, _("Move to Top (draw first)"));
			popmenu->Append(ID_POPUP_TO_BOTTOM, _("Move to Bottom (draw last)"));
			popmenu->AppendSeparator();
		}
		popmenu->Append(ID_POPUP_SHOWALL, _("Show All"));
		popmenu->Append(ID_POPUP_HIDEALL, _("Hide All"));
		PopupMenu(popmenu);
		delete popmenu;
	}
}

void MyTreeCtrl::OnBeginDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnEndDrag(wxTreeEvent& event)
{
}

void MyTreeCtrl::OnBeginLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnBeginLabelEdit");

	// for testing, prevent this items label editing
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't edit this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnEndLabelEdit(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnEndLabelEdit");

	// don't allow anything except letters in the labels
	if ( !event.GetLabel().IsWord() )
	{
		wxMessageBox("The label should contain only letters.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemCollapsing(wxTreeEvent& event)
{
#if 0
	wxLogMessage("OnItemCollapsing");

	// for testing, prevent the user from collapsing the first child folder
	wxTreeItemId itemId = event.GetItem();
	if ( IsTestItem(itemId) )
	{
		wxMessageBox("You can't collapse this item.");

		event.Veto();
	}
#endif
}

void MyTreeCtrl::OnItemActivated(wxTreeEvent& event)
{
#if 0
	// show some info about this item
	wxTreeItemId itemId = event.GetItem();
	MyTreeItemData *item = (MyTreeItemData *)GetItemData(itemId);

	if ( item != NULL )
	{
		item->ShowInfo(this);
	}
	wxLogMessage("OnItemActivated");
#endif
}

void MyTreeCtrl::OnRMouseDClick(wxMouseEvent& event)
{
#if 0
	wxTreeItemId id = HitTest(event.GetPosition());
	if ( !id )
		wxLogMessage("No item under mouse");
	else
	{
		MyTreeItemData *item = (MyTreeItemData *)GetItemData(id);
		if ( item )
			wxLogMessage("Item '%s' under mouse", item->GetDesc());
	}
#endif
}

/////////////////////////////////////////////////

BEGIN_EVENT_TABLE(MyTreeCtrl, wxTreeCtrl)
EVT_TREE_BEGIN_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginDrag)
EVT_TREE_BEGIN_RDRAG(LayerTree_Ctrl, MyTreeCtrl::OnBeginRDrag)
EVT_TREE_END_DRAG(LayerTree_Ctrl, MyTreeCtrl::OnEndDrag)
EVT_TREE_BEGIN_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnBeginLabelEdit)
EVT_TREE_END_LABEL_EDIT(LayerTree_Ctrl, MyTreeCtrl::OnEndLabelEdit)
EVT_TREE_DELETE_ITEM(LayerTree_Ctrl, MyTreeCtrl::OnDeleteItem)
EVT_TREE_ITEM_EXPANDED(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanded)
EVT_TREE_ITEM_EXPANDING(LayerTree_Ctrl, MyTreeCtrl::OnItemExpanding)
EVT_TREE_ITEM_COLLAPSED(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsed)
EVT_TREE_ITEM_COLLAPSING(LayerTree_Ctrl, MyTreeCtrl::OnItemCollapsing)
EVT_TREE_ITEM_RIGHT_CLICK(LayerTree_Ctrl, MyTreeCtrl::OnItemRightClick)
EVT_TREE_SEL_CHANGED(LayerTree_Ctrl, MyTreeCtrl::OnSelChanged)
EVT_TREE_SEL_CHANGING(LayerTree_Ctrl, MyTreeCtrl::OnSelChanging)
EVT_TREE_KEY_DOWN(LayerTree_Ctrl, MyTreeCtrl::OnTreeKeyDown)
EVT_TREE_ITEM_ACTIVATED(LayerTree_Ctrl, MyTreeCtrl::OnItemActivated)
EVT_RIGHT_DCLICK(MyTreeCtrl::OnRMouseDClick)
END_EVENT_TABLE()

<|endoftext|>


<commit_before>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "StringTests.h"
#include "OgreStringConverter.h"
#include "OgreVector3.h"
#include "OgreQuaternion.h"
#include "OgreMatrix4.h"
#include "OgreColourValue.h"

using namespace Ogre;

// Register the test suite

//--------------------------------------------------------------------------
void StringTests::SetUp()
{
    testFileNoPath = "testfile.txt";
    testFileRelativePathUnix = "this/is/relative/testfile.txt";
    testFileRelativePathWindows = "this\\is\\relative\\testfile.txt";
    testFileAbsolutePathUnix = "/this/is/absolute/testfile.txt";
    testFileAbsolutePathWindows = "c:\\this\\is\\absolute\\testfile.txt";
}
//--------------------------------------------------------------------------
void StringTests::TearDown()
{
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameNoPath)
{
    String basename, path;
    StringUtil::splitFilename(testFileNoPath, basename, path);

    EXPECT_EQ(testFileNoPath, basename);
    EXPECT_TRUE(path.empty());
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameRelativePath)
{
    String basename, path;

    // Unix
    StringUtil::splitFilename(testFileRelativePathUnix, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("this/is/relative/"), path);

    // Windows
    StringUtil::splitFilename(testFileRelativePathWindows, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("this/is/relative/"), path);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameAbsolutePath)
{
    String basename, path;

    // Unix
    StringUtil::splitFilename(testFileAbsolutePathUnix, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("/this/is/absolute/"), path);

    // Windows
    StringUtil::splitFilename(testFileAbsolutePathWindows, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("c:/this/is/absolute/"), path);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchCaseSensitive)
{
    // Test positive
    EXPECT_TRUE(StringUtil::match(testFileNoPath, testFileNoPath, true));

    // Test negative
    String upperCase = testFileNoPath;
    StringUtil::toUpperCase(upperCase);
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, upperCase, true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchCaseInSensitive)
{
    // Test positive
    EXPECT_TRUE(StringUtil::match(testFileNoPath, testFileNoPath, false));

    // Test positive
    String upperCase = testFileNoPath;
    StringUtil::toUpperCase(upperCase);
    EXPECT_TRUE(StringUtil::match(testFileNoPath, upperCase, false));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobAll)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobStart)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*stfile.txt", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "*astfile.txt", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobEnd)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "testfile.*", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "testfile.d*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobStartAndEnd)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*stfile.*", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "*astfile.d*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobMiddle)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "test*.txt", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "last*.txt*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchSuperGlobtastic)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*e*tf*e.t*t", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseReal)
{
    Real r = 23.454;

    String s = StringConverter::toString(r);
    Real t = StringConverter::parseReal(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseInt)
{
    int r = 223546;

    String s = StringConverter::toString(r);
    int t = StringConverter::parseInt(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseLong)
{
    long r = -2147483647;

    String s = StringConverter::toString(r);
    long t = StringConverter::parseLong(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseUnsignedLong)
{
    unsigned long r = 4294967295UL;

    String s = StringConverter::toString(r);
    unsigned long t = StringConverter::parseUnsignedLong(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseVector3)
{
    Vector3 r(0.12, 3.22, -4.04);

    String s = StringConverter::toString(r);
    Vector3 t = StringConverter::parseVector3(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseMatrix4)
{
    Matrix4 r(1.12, 0, 0, 34, 0, 0.87, 0, 20, 0, 0, 0.56, 10, 0, 0, 0, 1);

    String s = StringConverter::toString(r);
    Matrix4 t = StringConverter::parseMatrix4(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseQuaternion)
{
    Quaternion r(1.12, 0.87, 0.67, 1);

    String s = StringConverter::toString(r);
    Quaternion t = StringConverter::parseQuaternion(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseBool)
{
    bool r = true;
    String s = StringConverter::toString(r);
    bool t = StringConverter::parseBool(s);
    EXPECT_EQ(r, t);

    r = false;
    s = StringConverter::toString(r);
    t = StringConverter::parseBool(s);
    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseColourValue)
{
    ColourValue r(0.34, 0.44, 0.77, 1.0);

    String s = StringConverter::toString(r);
    ColourValue t = StringConverter::parseColourValue(s);
    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,EndsWith)
{
    String s = "Hello World!";

    EXPECT_TRUE(StringUtil::endsWith(s, "world!"));
    EXPECT_FALSE(StringUtil::endsWith(s, "hello"));
    EXPECT_FALSE(StringUtil::endsWith(s, "world!", false));
    EXPECT_FALSE(StringUtil::endsWith(s, "", false));
}

TEST_F(StringTests,StartsWith)
{
    String s = "Hello World!";

    EXPECT_TRUE(StringUtil::startsWith(s, "hello"));
    EXPECT_FALSE(StringUtil::startsWith(s, "world"));
    EXPECT_FALSE(StringUtil::startsWith(s, "hello", false));
    EXPECT_FALSE(StringUtil::startsWith(s, "", false));
}
<commit_msg>StringTests: verify that we are independent of LC_NUMERIC<commit_after>/*
-----------------------------------------------------------------------------
This source file is part of OGRE
(Object-oriented Graphics Rendering Engine)
For the latest info, see http://www.ogre3d.org/

Copyright (c) 2000-2014 Torus Knot Software Ltd

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
-----------------------------------------------------------------------------
*/
#include "StringTests.h"
#include "OgreStringConverter.h"
#include "OgreVector3.h"
#include "OgreQuaternion.h"
#include "OgreMatrix4.h"
#include "OgreColourValue.h"

using namespace Ogre;

// Register the test suite

//--------------------------------------------------------------------------
void StringTests::SetUp()
{
    testFileNoPath = "testfile.txt";
    testFileRelativePathUnix = "this/is/relative/testfile.txt";
    testFileRelativePathWindows = "this\\is\\relative\\testfile.txt";
    testFileAbsolutePathUnix = "/this/is/absolute/testfile.txt";
    testFileAbsolutePathWindows = "c:\\this\\is\\absolute\\testfile.txt";
    setlocale(LC_NUMERIC, "");
}
//--------------------------------------------------------------------------
void StringTests::TearDown()
{
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameNoPath)
{
    String basename, path;
    StringUtil::splitFilename(testFileNoPath, basename, path);

    EXPECT_EQ(testFileNoPath, basename);
    EXPECT_TRUE(path.empty());
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameRelativePath)
{
    String basename, path;

    // Unix
    StringUtil::splitFilename(testFileRelativePathUnix, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("this/is/relative/"), path);

    // Windows
    StringUtil::splitFilename(testFileRelativePathWindows, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("this/is/relative/"), path);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,SplitFileNameAbsolutePath)
{
    String basename, path;

    // Unix
    StringUtil::splitFilename(testFileAbsolutePathUnix, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("/this/is/absolute/"), path);

    // Windows
    StringUtil::splitFilename(testFileAbsolutePathWindows, basename, path);
    EXPECT_EQ(String("testfile.txt"), basename);
    EXPECT_EQ(String("c:/this/is/absolute/"), path);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchCaseSensitive)
{
    // Test positive
    EXPECT_TRUE(StringUtil::match(testFileNoPath, testFileNoPath, true));

    // Test negative
    String upperCase = testFileNoPath;
    StringUtil::toUpperCase(upperCase);
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, upperCase, true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchCaseInSensitive)
{
    // Test positive
    EXPECT_TRUE(StringUtil::match(testFileNoPath, testFileNoPath, false));

    // Test positive
    String upperCase = testFileNoPath;
    StringUtil::toUpperCase(upperCase);
    EXPECT_TRUE(StringUtil::match(testFileNoPath, upperCase, false));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobAll)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobStart)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*stfile.txt", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "*astfile.txt", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobEnd)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "testfile.*", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "testfile.d*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobStartAndEnd)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*stfile.*", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "*astfile.d*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchGlobMiddle)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "test*.txt", true));
    EXPECT_TRUE(!StringUtil::match(testFileNoPath, "last*.txt*", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,MatchSuperGlobtastic)
{
    EXPECT_TRUE(StringUtil::match(testFileNoPath, "*e*tf*e.t*t", true));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseReal)
{
    Real r = 23.454;

    String s = StringConverter::toString(r);

    EXPECT_EQ(r, StringConverter::parseReal(s));
    EXPECT_EQ(r, StringConverter::parseReal("23.454"));
    EXPECT_NE(r, StringConverter::parseReal("23,454"));
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseInt)
{
    int r = 223546;

    String s = StringConverter::toString(r);
    int t = StringConverter::parseInt(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseLong)
{
    long r = -2147483647;

    String s = StringConverter::toString(r);
    long t = StringConverter::parseLong(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseUnsignedLong)
{
    unsigned long r = 4294967295UL;

    String s = StringConverter::toString(r);
    unsigned long t = StringConverter::parseUnsignedLong(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseVector3)
{
    Vector3 r(0.12, 3.22, -4.04);

    String s = StringConverter::toString(r);
    Vector3 t = StringConverter::parseVector3(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseMatrix4)
{
    Matrix4 r(1.12, 0, 0, 34, 0, 0.87, 0, 20, 0, 0, 0.56, 10, 0, 0, 0, 1);

    String s = StringConverter::toString(r);
    Matrix4 t = StringConverter::parseMatrix4(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseQuaternion)
{
    Quaternion r(1.12, 0.87, 0.67, 1);

    String s = StringConverter::toString(r);
    Quaternion t = StringConverter::parseQuaternion(s);

    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseBool)
{
    bool r = true;
    String s = StringConverter::toString(r);
    bool t = StringConverter::parseBool(s);
    EXPECT_EQ(r, t);

    r = false;
    s = StringConverter::toString(r);
    t = StringConverter::parseBool(s);
    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,ParseColourValue)
{
    ColourValue r(0.34, 0.44, 0.77, 1.0);

    String s = StringConverter::toString(r);
    ColourValue t = StringConverter::parseColourValue(s);
    EXPECT_EQ(r, t);
}
//--------------------------------------------------------------------------
TEST_F(StringTests,EndsWith)
{
    String s = "Hello World!";

    EXPECT_TRUE(StringUtil::endsWith(s, "world!"));
    EXPECT_FALSE(StringUtil::endsWith(s, "hello"));
    EXPECT_FALSE(StringUtil::endsWith(s, "world!", false));
    EXPECT_FALSE(StringUtil::endsWith(s, "", false));
}

TEST_F(StringTests,StartsWith)
{
    String s = "Hello World!";

    EXPECT_TRUE(StringUtil::startsWith(s, "hello"));
    EXPECT_FALSE(StringUtil::startsWith(s, "world"));
    EXPECT_FALSE(StringUtil::startsWith(s, "hello", false));
    EXPECT_FALSE(StringUtil::startsWith(s, "", false));
}
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME.  DO NOT ALTER THE FORMAT OR ENTER
   ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD EXTRA INFORMATION,
   DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.3.0 " __DATE__ BUILDIDSTR " $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<commit_msg>Version string for 7.3.1 pre-release.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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.
 *
 ***************************************************************/

/*
   This is some wisdom from Cygnus's web page.  If you just try to use
   the "stringify" operator on a preprocessor directive, you'd get
   "PLATFORM", not "Intel Linux" (or whatever the value of PLATFORM
   is).  That's because the stringify operator is a special case, and
   the preprocessor isn't allowed to expand things that are passed to
   it.  However, by defining two layers of macros, you get the right
   behavior, since the first pass converts:

   xstr(PLATFORM) -> str(Intel Linux)

   and the next pass gives:

   str(Intel Linux) -> "Intel Linux"

   This is exactly what we want, so we use it.  -Derek Wright and Jeff
   Ballard, 12/2/99

   Also, because the NT build system is totally different, we have to
   define the correct platform string right in here. :( -Derek 12/3/99
*/

#define xstr(s) str(s)
#define str(s) #s

#if defined(WIN32)
#define PLATFORM INTEL-WINNT50
#endif

/* Via configure, one may have specified a particular buildid string to use
	in the version string. So honor that request here. */
#if defined(BUILDID)
#define BUILDIDSTR " BuildID: " xstr(BUILDID)
#else
#define BUILDIDSTR ""
#endif

/* Here is the version string - update before a public release */
/* --- IMPORTANT!  THE FORMAT OF THE VERSION STRING IS VERY STRICT
   BECAUSE IT IS PARSED AT RUNTIME.  DO NOT ALTER THE FORMAT OR ENTER
   ANYTHING EXTRA BEFORE THE DATE.  IF YOU WISH TO ADD EXTRA INFORMATION,
   DO SO _AFTER_ THE BUILDIDSTR AND BEFORE THE TRAILING '$' CHARACTER.
   EXAMPLES:
       $CondorVersion: 6.9.5 " __DATE__ BUILDIDSTR " WinNTPreview $ [OK]
	   $CondorVersion: 6.9.5 WinNTPreview " __DATE__ BUILDIDSTR " $ [WRONG!!!]
   Any questions?  See Todd or Derek.  Note: if you mess it up, DaemonCore
   will EXCEPT at startup time.
*/

static char* CondorVersionString = "$CondorVersion: 7.3.1 " __DATE__ BUILDIDSTR " PRE-RELEASE-UWCS $";

/* Here is the platform string.  You don't need to edit this */
static char* CondorPlatformString = "$CondorPlatform: " xstr(PLATFORM) " $";

extern "C" {

const char*
CondorVersion( void )
{
	return CondorVersionString;
}

const char*
CondorPlatform( void )
{
	return CondorPlatformString;
}

} /* extern "C" */

<|endoftext|>


<commit_before>#include "HelloWorld2.h"
#include "NFComm/NFCore/NFCObject.h"

bool HelloWorld2::Init()
{
    //ʼ

    std::cout << "Hello, world2, Init" << std::endl;

    return true;
}

int HelloWorld2::OnPropertyCallBackEvent( const NFIDENTID& self, const std::string& strProperty, const NFIDataList& oldVarList, const NFIDataList& newVarList )
{
    //Իص¼ֻҪֵб仯ͻᱻص
    std::cout << "OnPropertyCallBackEvent Property: " << strProperty << " OldValue: " << oldVarList.Int(0) << " NewValue: " << newVarList.Int(0) << std::endl;

    return 0;
}

bool HelloWorld2::AfterInit()
{
// #ifdef NF_USE_ACTOR
//     if(pPluginManager->GetActorID() == NFIActorManager::EACTOR_MAIN)
// #endif
    {
        //ʼ
        std::cout << "Hello, world2, AfterInit" << std::endl;

        NFIObject* pObject = new NFCObject(NFIDENTID(0, 1), pPluginManager);
        pObject->GetPropertyManager()->AddProperty(pObject->Self(), "Hello", TDATA_STRING, true, true, true, true, 0, "");
        pObject->GetPropertyManager()->AddProperty(pObject->Self(), "World", TDATA_INT, true, true, true, true, 0, "");

        pObject->SetPropertyInt("World", 1111);

        const int nProperty1 = pObject->GetPropertyInt("World");
        std::cout << "Property World:" << nProperty1 << std::endl;

        //¼
        pObject->AddPropertyCallBack("World", this, &HelloWorld2::OnPropertyCallBackEvent);

        pObject->SetPropertyInt("World", 2222);

        const int nProperty2 = pObject->GetPropertyInt("World");
        std::cout << "Property World:" << nProperty2 << std::endl;
    }

    return true;
}

bool HelloWorld2::Execute( const float fLasFrametime, const float fStartedTime )
{
    //ÿִ֡
    //std::cout << "Hello, world2, Execute" << std::endl;

    return true;
}

bool HelloWorld2::BeforeShut()
{
    //ʼ֮ǰ
    std::cout << "Hello, world2, BeforeShut" << std::endl;

    return true;
}

bool HelloWorld2::Shut()
{
    //ʼ
    std::cout << "Hello, world2, Shut" << std::endl;

    return true;
}
<commit_msg>add comments for tutorial2<commit_after>#include "HelloWorld2.h"
#include "NFComm/NFCore/NFCObject.h"

bool HelloWorld2::Init()
{
    //ʼ

    std::cout << "Hello, world2, Init" << std::endl;

    return true;
}

int HelloWorld2::OnPropertyCallBackEvent( const NFIDENTID& self, const std::string& strProperty, const NFIDataList& oldVarList, const NFIDataList& newVarList )
{
    //Իص¼ֻҪֵб仯ͻᱻص
    std::cout << "OnPropertyCallBackEvent Property: " << strProperty << " OldValue: " << oldVarList.Int(0) << " NewValue: " << newVarList.Int(0) << std::endl;

    return 0;
}

bool HelloWorld2::AfterInit()
{
// #ifdef NF_USE_ACTOR
//     if(pPluginManager->GetActorID() == NFIActorManager::EACTOR_MAIN)
// #endif
    {
        std::cout << "Hello, world2, AfterInit" << std::endl;

		//created a object for this test
        NFIObject* pObject = new NFCObject(NFIDENTID(0, 1), pPluginManager);

		//add a property name is "Hello" of this object
        pObject->GetPropertyManager()->AddProperty(pObject->Self(), "Hello", TDATA_STRING, true, true, true, true, 0, "");
		//add a property name is "World" of this object
        pObject->GetPropertyManager()->AddProperty(pObject->Self(), "World", TDATA_INT, true, true, true, true, 0, "");

		//set the "world" property value as 1111
        pObject->SetPropertyInt("World", 1111);

		//get the "world" property value and printf it
        const int nProperty1 = pObject->GetPropertyInt("World");
        std::cout << "Property World:" << nProperty1 << std::endl;

        //add a call back functin for "world" property
        pObject->AddPropertyCallBack("World", this, &HelloWorld2::OnPropertyCallBackEvent);

		////set the "world" property value as 2222[than the function "HelloWorld2::OnPropertyCallBackEvent" will be called]
        pObject->SetPropertyInt("World", 2222);

		//get the "world" property value and printf it
        const int nProperty2 = pObject->GetPropertyInt("World");
        std::cout << "Property World:" << nProperty2 << std::endl;
    }

    return true;
}

bool HelloWorld2::Execute( const float fLasFrametime, const float fStartedTime )
{
    //ÿִ֡
    //std::cout << "Hello, world2, Execute" << std::endl;

    return true;
}

bool HelloWorld2::BeforeShut()
{
    //ʼ֮ǰ
    std::cout << "Hello, world2, BeforeShut" << std::endl;

    return true;
}

bool HelloWorld2::Shut()
{
    //ʼ
    std::cout << "Hello, world2, Shut" << std::endl;

    return true;
}
<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(Handler::HANDLER_DONE);
  }

  char* filename = nullptr;

  if (TRI_GetTempName("uploads", &filename, false) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);
  bool multiPart = false;

  if (found) {
    multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(Handler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &json);
  TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, &json, "filename", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, fullName, strlen(fullName)));
  TRI_Free(TRI_CORE_MEM_ZONE, fullName);

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);

  // success
  return status_t(Handler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<commit_msg>reduce var scope<commit_after>////////////////////////////////////////////////////////////////////////////////
/// @brief upload request handler
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2014 ArangoDB GmbH, Cologne, Germany
/// Copyright 2004-2014 triAGENS GmbH, Cologne, Germany
///
/// 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.
///
/// Copyright holder is ArangoDB GmbH, Cologne, Germany
///
/// @author Jan Steemann
/// @author Copyright 2014, ArangoDB GmbH, Cologne, Germany
/// @author Copyright 2012-2014, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

#include "RestUploadHandler.h"

#include "Basics/FileUtils.h"
#include "Basics/files.h"
#include "Basics/logging.h"
#include "Basics/StringUtils.h"
#include "HttpServer/HttpServer.h"
#include "Rest/HttpRequest.h"

using namespace std;
using namespace triagens::basics;
using namespace triagens::rest;
using namespace triagens::arango;

// -----------------------------------------------------------------------------
// --SECTION--                                      constructors and destructors
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// @brief constructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::RestUploadHandler (HttpRequest* request)
  : RestVocbaseBaseHandler(request) {
}

////////////////////////////////////////////////////////////////////////////////
/// @brief destructor
////////////////////////////////////////////////////////////////////////////////

RestUploadHandler::~RestUploadHandler () {
}

// -----------------------------------------------------------------------------
// --SECTION--                                                   Handler methods
// -----------------------------------------------------------------------------

////////////////////////////////////////////////////////////////////////////////
/// {@inheritDoc}
////////////////////////////////////////////////////////////////////////////////

Handler::status_t RestUploadHandler::execute () {
  // extract the request type
  const HttpRequest::HttpRequestType type = _request->requestType();

  if (type != HttpRequest::HTTP_REQUEST_POST) {
    generateError(HttpResponse::METHOD_NOT_ALLOWED, TRI_ERROR_HTTP_METHOD_NOT_ALLOWED);

    return status_t(Handler::HANDLER_DONE);
  }

  char* filename = nullptr;

  if (TRI_GetTempName("uploads", &filename, false) != TRI_ERROR_NO_ERROR) {
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not generate temp file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* relative = TRI_GetFilename(filename);

  LOG_TRACE("saving uploaded file of length %llu in file '%s', relative '%s'",
            (unsigned long long) _request->bodySize(),
            filename,
            relative);

  char const* body = _request->body();
  size_t bodySize  = _request->bodySize();

  bool found;
  char const* value = _request->value("multipart", found);

  if (found) {
    bool multiPart = triagens::basics::StringUtils::boolean(value);

    if (multiPart) {
      if (! parseMultiPart(body, bodySize)) {
        TRI_Free(TRI_CORE_MEM_ZONE, relative);
        TRI_Free(TRI_CORE_MEM_ZONE, filename);
        generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "invalid multipart request");
        return status_t(Handler::HANDLER_FAILED);
      }
    }
  }

  try {
    FileUtils::spit(string(filename), body, bodySize);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
  }
  catch (...) {
    TRI_Free(TRI_CORE_MEM_ZONE, relative);
    TRI_Free(TRI_CORE_MEM_ZONE, filename);
    generateError(HttpResponse::SERVER_ERROR, TRI_ERROR_INTERNAL, "could not save file");
    return status_t(Handler::HANDLER_FAILED);
  }

  char* fullName = TRI_Concatenate2File("uploads", relative);
  TRI_Free(TRI_CORE_MEM_ZONE, relative);

  // create the response
  _response = createResponse(HttpResponse::CREATED);
  _response->setContentType("application/json; charset=utf-8");

  TRI_json_t json;

  TRI_InitObjectJson(TRI_UNKNOWN_MEM_ZONE, &json);
  TRI_Insert3ObjectJson(TRI_UNKNOWN_MEM_ZONE, &json, "filename", TRI_CreateStringCopyJson(TRI_UNKNOWN_MEM_ZONE, fullName, strlen(fullName)));
  TRI_Free(TRI_CORE_MEM_ZONE, fullName);

  generateResult(HttpResponse::CREATED, &json);
  TRI_DestroyJson(TRI_UNKNOWN_MEM_ZONE, &json);

  // success
  return status_t(Handler::HANDLER_DONE);
}

////////////////////////////////////////////////////////////////////////////////
/// @brief parses a multi-part request body and determines the boundaries of
/// its first element
////////////////////////////////////////////////////////////////////////////////

bool RestUploadHandler::parseMultiPart (char const*& body,
                                        size_t& length) {
  char const* beg = _request->body();
  char const* end = beg + _request->bodySize();

  while (beg < end && (*beg == '\r' || *beg == '\n' || *beg == ' ')) {
    ++beg;
  }

  // find delimiter
  char const* ptr = beg;
  while (ptr < end && *ptr == '-') {
    ++ptr;
  }

  while (ptr < end && *ptr != '\r' && *ptr != '\n') {
    ++ptr;
  }
  if (ptr == beg) {
    // oops
    return false;
  }

  std::string const delimiter(beg, ptr - beg);
  if (ptr < end && *ptr == '\r') {
    ++ptr;
  }
  if (ptr < end && *ptr == '\n') {
    ++ptr;
  }

  std::vector<std::pair<char const*, size_t>> parts;

  while (ptr < end) {
    char const* p = TRI_IsContainedMemory(ptr, end - ptr, delimiter.c_str(), delimiter.size());
    if (p == nullptr || p + delimiter.size() + 2 >= end || p - 2 <= ptr) {
      return false;
    }

    char const* q = p;
    if (*(q - 1) == '\n') {
      --q;
    }
    if (*(q - 1) == '\r') {
      --q;
    }

    parts.push_back(std::make_pair(ptr, q - ptr));
    ptr = p + delimiter.size();
    if (*ptr == '-' && *(ptr + 1) == '-') {
      // eom
      break;
    }
    if (*ptr == '\r') {
      ++ptr;
    }
    if (ptr < end && *ptr == '\n') {
      ++ptr;
    }
  }

  for (auto& part : parts) {
    auto ptr = part.first;
    auto end = part.first + part.second;
    char const* data = nullptr;

    while (ptr < end) {
      while (ptr < end && *ptr == ' ') {
        ++ptr;
      }
      if (ptr < end && (*ptr == '\r' || *ptr == '\n')) {
        // end of headers
        if (*ptr == '\r') {
          ++ptr;
        }
        if (ptr < end && *ptr == '\n') {
          ++ptr;
        }
        data = ptr;
        break;
      }

      // header line
      char const* eol = TRI_IsContainedMemory(ptr, end - ptr, "\r\n", 2);

      if (eol == nullptr) {
        eol = TRI_IsContainedMemory(ptr, end - ptr, "\n", 1);
      }

      if (eol == nullptr) {
        return false;
      }

      char const* colon = TRI_IsContainedMemory(ptr, end - ptr, ":", 1);
      if (colon == nullptr) {
        return false;
      }

      char const* p = colon;
      while (p > ptr && *(p - 1) == ' ') {
        --p;
      }

      ++colon;
      while (colon < eol && *colon == ' ') {
        ++colon;
      }

      char const* q = eol;
      while (q > ptr && *(q - 1) == ' ') {
        --q;
      }

      ptr = eol;
      if (*ptr == '\r') {
        ++ptr;
      }
      if (ptr < end && *ptr == '\n') {
        ++ptr;
      }
    }

    if (data == nullptr) {
      return false;
    }

    body = data;
    length = static_cast<size_t>(end - data);

    // stop after the first found element
    break;
  }

  return true;
}

// -----------------------------------------------------------------------------
// --SECTION--                                                       END-OF-FILE
// -----------------------------------------------------------------------------

// Local Variables:
// mode: outline-minor
// outline-regexp: "/// @brief\\|/// {@inheritDoc}\\|/// @page\\|// --SECTION--\\|/// @\\}"
// End:
<|endoftext|>


<commit_before><commit_msg>core: fixed absolute on booleans<commit_after><|endoftext|>