<commit_before>#include "TH1.h"
#include "TF1.h"
#include "TFile.h"
#include "TRandom.h"
#include "Math/IParamFunction.h"
#include "TFitResult.h"
#include "TError.h"
#include "TROOT.h"
#include "Math/MinimizerOptions.h"

#include <chrono>

bool compareResult(double v1, double v2, std::string s = "", double tol = 0.01)
{
   // compare v1 with reference v2
   //  // give 1% tolerance
   if (std::abs(v1 - v2) < tol * std::abs(v2)) return true;
   std::cerr << s << " Failed comparison of fit results \t chi2 = " << v1 << "   it should be = " << v2 << std::endl;
   return false;
}

template <class T>
T func(const T *data, const double *params)
{
   return params[0] * exp(-(*data + (-130.)) * (*data + (-130.)) / 2) +
          params[1] * exp(-(params[2] * (*data * (0.01)) - params[3] * ((*data) * (0.01)) * ((*data) * (0.01))));
}

int main()
{

   TF1 *f = new TF1("fvCore", func<double>, 100, 200, 4);
   f->SetParameters(1, 1000, 7.5, 1.5);

   // NBins not multiple of SIMD vector size, testing padding
   TH1D h1f("h1f", "Test random numbers", 12801, 100, 200);
   gRandom->SetSeed(1);
   h1f.FillRandom("fvCore", 1000000);

   ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2");

   std::chrono::time_point<std::chrono::system_clock> start, end;
   std::chrono::duration<double> duration;
   std::cout << "\n **FIT: Chi2 **\n\n";
   start = std::chrono::system_clock::now();
   auto r1 = h1f.Fit(f, "S");
   if ((Int_t)r1 != 0) {
      Error("testBinnedFitExecPolicy", "Sequential Chi2 Fit failed!");
      return -1;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Sequential Chi2 Fit: " << duration.count() << std::endl;

   std::cout << "\n **FIT: Binned Likelihood **\n\n";
   f->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto rL1 = h1f.Fit(f, "S L");
   if ((Int_t)rL1 != 0) {
      Error("testBinnedFitExecPolicy", "Sequential  Binned Likelihood Fit failed!");
      return -1;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Sequential  Binned Likelihood Fit: " << duration.count() << std::endl;

#ifdef R__USE_IMT
   std::cout << "\n **FIT: Multithreaded Chi2 **\n\n";
   f->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto r2 = h1f.Fit(f, "MULTITHREAD S");
   if ((Int_t)r2 != 0) {
      Error("testBinnedFitExecPolicy", "Multithreaded Chi2 Fit failed!");
      return -1;
   } else {
      if (!compareResult(r2->MinFcnValue(), r1->MinFcnValue(), "Mutithreaded Chi2 Fit: "))
         return 1;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Mutithreaded Chi2 Fit: " << duration.count() << std::endl;

   std::cout << "\n **FIT: Multithreaded Binned Likelihood **\n\n";
   f->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto rL2 = h1f.Fit(f, "MULTITHREAD S L");
   if ((Int_t)rL2 != 0) {
      Error("testBinnedFitExecPolicy", "Multithreaded Binned Likelihood Fit failed!");
      return -1;
   } else {
      if (!compareResult(rL2->MinFcnValue(), rL1->MinFcnValue(), "Mutithreaded Binned Likelihood Fit (PoissonLogL): "))
         return 2;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Mutithreaded Binned Likelihood Fit :" << duration.count() << std::endl;
#endif

#ifdef R__HAS_VECCORE
   TF1 *fvecCore = new TF1("fvCore", func<ROOT::Double_v>, 100, 200, 4);

   std::cout << "\n **FIT: Vectorized Chi2 **\n\n";
   fvecCore->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto r3 = h1f.Fit(fvecCore, "S");
   if ((Int_t)r3 != 0) {
      Error("testBinnedFitExecPolicy", "Vectorized Chi2 Fit failed!");
      return -1;
   } else {
      if (!compareResult(r3->MinFcnValue(), r1->MinFcnValue(), "Vectorized Chi2 Fit: "))
         return 3;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Vectorized Chi2 Fit: " << duration.count() << std::endl;

   std::cout << "\n **FIT: Vectorized Binned Likelihood **\n\n";
   fvecCore->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto rL3 = h1f.Fit(fvecCore, "S L");
   if ((Int_t)rL3 != 0) {
      Error("testBinnedFitExecPolicy", "Vectorized Binned Likelihood Fit failed!");
      return -1;
   } else {
      if (!compareResult(rL3->MinFcnValue(), rL1->MinFcnValue(),
                         "Vectorized Binned Likelihood Fit (PoissonLogL) Fit: "))
         return 4;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Vectorized Binned Likelihood Fit: " << duration.count() << std::endl;

#ifdef R__USE_IMT
   std::cout << "\n **FIT: Mutithreaded vectorized Chi2 **\n\n";
   fvecCore->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto r4 = h1f.Fit(fvecCore, "MULTITHREAD S");
   if ((Int_t)r4 != 0) {
      Error("testBinnedFitExecPolicy", "Mutithreaded vectorized Chi2 Fit failed!");
      return -1;
   } else {
      if (!compareResult(r4->MinFcnValue(), r1->MinFcnValue(), "Mutithreaded vectorized Chi2 Fit: "))
         return 5;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the Mutithreaded vectorized Chi2 Fit: " << duration.count() << std::endl;

   std::cout << "\n **FIT: Multithreaded and vectorized Binned Likelihood **\n\n";
   fvecCore->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto rL4 = h1f.Fit(fvecCore, "MULTITHREAD S L");
   if ((Int_t)rL4 != 0) {
      Error("testBinnedFitExecPolicy", "Multithreaded Binned Likelihood vectorized Fit failed!");
      return -1;
   } else {
      if (!compareResult(rL4->MinFcnValue(), rL1->MinFcnValue(),
                         "Mutithreaded vectorized Binned Likelihood Fit (PoissonLogL) Fit: "))
         return 6;
   }
   end =  std::chrono::system_clock::now();
   duration = end - start;
   std::cout << "Time for the multithreaded+vectorized  Binned Likelihood Fit: " << duration.count() << std::endl;

#endif
#endif
   return 0;
}
<commit_msg>Improve BinnedFit test (#1068)<commit_after>#include "TH1.h"
#include "TF1.h"
#include "TRandom.h"
#include "TFitResult.h"
#include "TError.h"
#include "TROOT.h"
#include "Math/MinimizerOptions.h"
#include <chrono>

double tolerance = 0.01;

// Evaluating function
template <class T>
T func(const T *data, const double *params)
{
   return params[0] * exp(-(*data + (-130.)) * (*data + (-130.)) / 2) +
          params[1] * exp(-(params[2] * (*data * (0.01)) - params[3] * ((*data) * (0.01)) * ((*data) * (0.01))));
}

struct FitModelData {
   std::chrono::duration<double> refTime;
   TFitResultPtr refValue;
   std::string name;
   std::vector<double> speedups;
};

// Function that calls the fit, checks for numerical correctness and computes speed up
void benchmarkFit(TF1 *f, TH1D &h, const std::string &opt, const std::string &fit, FitModelData &model)
{
   std::chrono::time_point<std::chrono::system_clock> start, end;
   auto msg = fit + " " + model.name + " Fit";
   std::cout << "\n\n **" << msg << "**\n";
   f->SetParameters(1, 1000, 7.5, 1.5);
   start = std::chrono::system_clock::now();
   auto result = h.Fit(f, opt.c_str());
   end = std::chrono::system_clock::now();
   std::chrono::duration<double> duration = end - start;

   // Check if Fit succeeds
   if ((Int_t)result != 0) {
      Error("testBinnedFitExecPolicy", "%s failed!", msg.c_str());
      exit(-1);
   }

   if (!fit.compare("Sequential")) {
      // Save reference times and values
      model.refTime = end - start;
      model.refValue = result;
   } else {
      // Check if numerical result is within tolerance
      if (std::abs(result->MinFcnValue() - model.refValue->MinFcnValue()) >
          tolerance * std::abs(model.refValue->MinFcnValue())) {
         Error("testBinnedFitExecPolicy", "%s : Failed comparison of fit results \t FCN = %f, it should be = %f",
               msg.c_str(), result->MinFcnValue(), model.refValue->MinFcnValue());
         exit(-1);
      }
      // Compute speedup
      model.speedups.emplace_back(model.refTime.count() / duration.count() * result->NCalls() /
                                  model.refValue->NCalls());
   }

   std::cout << "Time for the " << msg << ": " << duration.count() << std::endl;
};

void printSpeedUps(std::vector<FitModelData> &models)
{
   std::cout.precision(2);
   std::string longestName =
      std::max_element(models.begin(), models.end(), [](const FitModelData &m1, const FitModelData &m2) {
         return m1.name.size() < m2.name.size();
      })->name;
   std::cout << std::endl << "\n   ***Speedups! (normalized to the number of calls)***" << std::endl;
   std::cout << std::string(longestName.size() + 1, ' ') << "|  MT    "
             << "|  VEC   "
             << "| MT+VEC " << std::endl;
   // Name field + value field + three bars + 1 extra
   std::cout << std::string(longestName.size() + 1 + 8 * 3 + 3 + 1, '-') << std::endl;
   for (auto m : models) {
      std::cout << m.name << std::string(longestName.size() - m.name.size() + 1, ' ');
      for (auto su : m.speedups)
         std::cout << std::fixed << "|  " << su << "  ";
      std::cout << std::endl;
   }
   std::cout << std::endl;
}

int main()
{

   ROOT::EnableImplicitMT();

   TF1 *f = new TF1("fvCore", func<double>, 100, 200, 4);
   f->SetParameters(1, 1000, 7.5, 1.5);

   // NBins not multiple of SIMD vector size, testing padding
   TH1D h1f("h1f", "Test random numbers", 12801, 100, 200);
   gRandom->SetSeed(1);
   h1f.FillRandom("fvCore", 1000000);
   ROOT::Math::MinimizerOptions::SetDefaultMinimizer("Minuit2");

   enum EModel { kChi2 = 0, kPoisson };
   std::vector<FitModelData> models(2);
   models[kChi2].name = "Chi2";
   models[kPoisson].name = "Binned Likelihood";

   // Start testing
   auto fit = "Sequential";
   benchmarkFit(f, h1f, "S SERIAL", fit, models[EModel::kChi2]);
   benchmarkFit(f, h1f, "SERIAL S L", fit, models[EModel::kPoisson]);

#ifdef R__USE_IMT
   fit = "Multithreaded";
   benchmarkFit(f, h1f, "S", fit, models[EModel::kChi2]);
   benchmarkFit(f, h1f, "S L", fit, models[EModel::kPoisson]);

#endif
#ifdef R__HAS_VECCORE
   TF1 *fvecCore = new TF1("fvCore", func<ROOT::Double_v>, 100, 200, 4);

   fit = "Vectorized";
   benchmarkFit(fvecCore, h1f, "SERIAL S", fit, models[EModel::kChi2]);
   benchmarkFit(fvecCore, h1f, "SERIAL S L", fit, models[EModel::kPoisson]);

#ifdef R__USE_IMT

   fit = "Mutithreaded and vectorized";
   benchmarkFit(fvecCore, h1f, "S", fit, models[EModel::kChi2]);
   benchmarkFit(fvecCore, h1f, "S L", fit, models[EModel::kPoisson]);

#endif
#endif
   printSpeedUps(models);
   return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <vector>
#include <cstdlib>
#include <cassert>
#include <cstdio>
#include <climits>

using namespace std;

const int INITIAL_SIZE = 64;

struct Pair
{
    Pair(string key, int value);

    string key;
    int value;
};

Pair::Pair(string key, int value)
{
    this->key = key;
    this->value = value;
}

// djb2
unsigned int hash(string s) {
    unsigned int hash = 5381;
    for(size_t i = 0; i < s.size(); i++) {
        hash = hash * 33 + static_cast<unsigned int>(s[i]);
    }
    return hash;
}

class KeyException { };

typedef Pair* PairPtr;

class StringIntMap
{
    public:
        // Contstructs a new map
        StringIntMap();

        ~StringIntMap();

        // Returns the number of elements in the map.
        int size();

        bool empty();

        // Adds the specified key to the map associated with the specified
        // value.
        // If there exists an entry in the map with the specified key, it
        // should be replaced with the specified value.
        void add(string item, int key);

        // Removes the value associated with the specified key.
        // or
        // Removes the pair with the specified key.
        void remove(string key);

        // Retrieves the item associated with the specified key.
        int& get(string key);

        // Returns true if and only if the map contains the specified key.
        bool contains(string key);

        int& operator[](string key);

        friend ostream& operator << (ostream& out, StringIntMap& m);

    private:
        PairPtr *map;
        int capacity;
        int count;

        int hash_key(string key);
        int get_pos(string key);
        void rebuild();
        void load_check();
};

StringIntMap::StringIntMap()
{
    capacity = INITIAL_SIZE;
    count = 0;
    map = new PairPtr[INITIAL_SIZE];
    for(int i = 0; i < capacity; i++) {
        map[i] = NULL;
    }
}

StringIntMap::~StringIntMap()
{
    for(int i = 0; i < capacity; i++) {
        if(map[i] != NULL) {
            delete map[i];
            map[i] = NULL;
        }
    }
    delete [] map;
}

int StringIntMap::size()
{
    return count;
}

int StringIntMap::hash_key(string key)
{
    return hash(key) % capacity;
}

void StringIntMap::load_check() {
    if(count / static_cast<double>(capacity) > 0.8) {
        rebuild();
    }
}

void StringIntMap::rebuild() {
    PairPtr *old_map = map;
    int old_cap = capacity;

    capacity *= 2;
    map = new PairPtr[capacity];

    for(int i = 0; i < capacity; i++) {
        map[i] = NULL;
    }

    for(int i = 0; i < old_cap; i++) {
        if(old_map[i] != NULL) {
            add(old_map[i]->key, old_map[i]->value);
            delete old_map[i];
        }
    }

    delete [] old_map;
}

bool StringIntMap::empty()
{
    return count == 0;
}

bool StringIntMap::contains(string key)
{
    return map[get_pos(key)] != NULL;
}

int StringIntMap::get_pos(string key)
{
    int h = hash_key(key);
    while(map[h] != NULL) {
        if(map[h]->key == key) {
            break;
        }
        h = (h + 1) % capacity;
    }
    return h;
}

int& StringIntMap::get(string key)
{
    int pos = get_pos(key);
    if(map[pos]!= NULL) {
        return map[pos]->value;
    }
    throw KeyException();
}

void StringIntMap::add(string key, int value)
{
    load_check();
    int pos = get_pos(key);
    if(map[pos]== NULL) {
        map[pos] = new Pair(key, value);
        count++;
    } else {
        map[pos]->value = value;
    }
}

void StringIntMap::remove(string key)
{
    int pos = get_pos(key);
    if(map[pos] != NULL) {
        delete map[pos];
        map[pos] = NULL;
        count--;
    }
}

int& StringIntMap::operator[] (string key)
{
    if(!contains(key)) {
        add(key, 0);
    }
    return get(key);
}

ostream& operator<< (ostream& out, StringIntMap& m)
{
    for(int i = 0; i < m.capacity; i++) {
        if(m.map[i] != NULL) {
            out << m.map[i]->key << ": " << m.map[i]->value << endl;
        }
    }
    return out;
}

int main()
{
    StringIntMap m;
    string s;
    while(cin >> s) {
        cout << s << endl;
        m[s]++;
    }
    cout << m;
}
<commit_msg>Remove remove<commit_after>#include <iostream>
#include <vector>
#include <cstdlib>
#include <cassert>
#include <cstdio>
#include <climits>

using namespace std;

const int INITIAL_SIZE = 64;

struct Pair
{
    Pair(string key, int value);

    string key;
    int value;
};

Pair::Pair(string key, int value)
{
    this->key = key;
    this->value = value;
}

// djb2
unsigned int hash(string s) {
    unsigned int hash = 5381;
    for(size_t i = 0; i < s.size(); i++) {
        hash = hash * 33 + static_cast<unsigned int>(s[i]);
    }
    return hash;
}

class KeyException { };

typedef Pair* PairPtr;

class StringIntMap
{
    public:
        // Contstructs a new map
        StringIntMap();

        ~StringIntMap();

        // Returns the number of elements in the map.
        int size();

        bool empty();

        // Adds the specified key to the map associated with the specified
        // value.
        // If there exists an entry in the map with the specified key, it
        // should be replaced with the specified value.
        void add(string item, int key);

        // Removes the value associated with the specified key.
        // or
        // Removes the pair with the specified key.
        void remove(string key);

        // Retrieves the item associated with the specified key.
        int& get(string key);

        // Returns true if and only if the map contains the specified key.
        bool contains(string key);

        int& operator[](string key);

        friend ostream& operator << (ostream& out, StringIntMap& m);

    private:
        PairPtr *map;
        int capacity;
        int count;

        int hash_key(string key);
        int get_pos(string key);
        void rebuild();
        void load_check();
};

StringIntMap::StringIntMap()
{
    capacity = INITIAL_SIZE;
    count = 0;
    map = new PairPtr[INITIAL_SIZE];
    for(int i = 0; i < capacity; i++) {
        map[i] = NULL;
    }
}

StringIntMap::~StringIntMap()
{
    for(int i = 0; i < capacity; i++) {
        if(map[i] != NULL) {
            delete map[i];
            map[i] = NULL;
        }
    }
    delete [] map;
}

int StringIntMap::size()
{
    return count;
}

int StringIntMap::hash_key(string key)
{
    return hash(key) % capacity;
}

void StringIntMap::load_check() {
    if(count / static_cast<double>(capacity) > 0.8) {
        rebuild();
    }
}

void StringIntMap::rebuild() {
    PairPtr *old_map = map;
    int old_cap = capacity;

    capacity *= 2;
    map = new PairPtr[capacity];

    for(int i = 0; i < capacity; i++) {
        map[i] = NULL;
    }

    for(int i = 0; i < old_cap; i++) {
        if(old_map[i] != NULL) {
            add(old_map[i]->key, old_map[i]->value);
            delete old_map[i];
        }
    }

    delete [] old_map;
}

bool StringIntMap::empty()
{
    return count == 0;
}

bool StringIntMap::contains(string key)
{
    return map[get_pos(key)] != NULL;
}

int StringIntMap::get_pos(string key)
{
    int h = hash_key(key);
    while(map[h] != NULL) {
        if(map[h]->key == key) {
            break;
        }
        h = (h + 1) % capacity;
    }
    return h;
}

int& StringIntMap::get(string key)
{
    int pos = get_pos(key);
    if(map[pos]!= NULL) {
        return map[pos]->value;
    }
    throw KeyException();
}

void StringIntMap::add(string key, int value)
{
    load_check();
    int pos = get_pos(key);
    if(map[pos]== NULL) {
        map[pos] = new Pair(key, value);
        count++;
    } else {
        map[pos]->value = value;
    }
}

void StringIntMap::remove(string key)
{
    // Hard B-)
}

int& StringIntMap::operator[] (string key)
{
    if(!contains(key)) {
        add(key, 0);
    }
    return get(key);
}

ostream& operator<< (ostream& out, StringIntMap& m)
{
    for(int i = 0; i < m.capacity; i++) {
        if(m.map[i] != NULL) {
            out << m.map[i]->key << ": " << m.map[i]->value << endl;
        }
    }
    return out;
}

int main()
{
    StringIntMap m;
    string s;
    while(cin >> s) {
        cout << s << endl;
        m[s]++;
    }
    cout << m;
}
<|endoftext|>


<commit_before>#include "builtin/bignum.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/integer.hpp"
#include "object_utils.hpp"
#include "ontology.hpp"
#include "configuration.hpp"

#include <tommath.h>

#define XST ((void*)state)

namespace rubinius {

  void Numeric::init(STATE) {
    GO(numeric).set(ontology::new_class(state, "Numeric"));
    // We inherit from this type in for example Rational
    // and that class shouldn't have NumericType set since
    // that can cause problems.
    G(numeric)->set_object_type(state, ObjectType);
  }

  void Integer::init(STATE) {
    GO(integer).set(ontology::new_class(state, "Integer", G(numeric)));
    G(integer)->set_object_type(state, IntegerType);
  }

  native_int Integer::bignum_to_native() {
    return as<Bignum>(this)->to_native();
  }

  unsigned int Integer::to_uint() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_uint();
    }

    return as<Bignum>(this)->to_uint();
  }

  long Integer::to_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_long();
    }

    return as<Bignum>(this)->to_long();
  }

  unsigned long Integer::to_ulong() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_ulong();
    }

    return as<Bignum>(this)->to_ulong();
  }

  long long Integer::to_long_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_long_long();
    }

    return as<Bignum>(this)->to_long_long();
  }

  unsigned long long Integer::to_ulong_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_ulong_long();
    }

    return as<Bignum>(this)->to_ulong_long();
  }

  bool Integer::positive_p() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->positive_p();
    }

    return as<Bignum>(this)->positive_p();
  }

  Integer* Integer::from(STATE, int num) {
#ifndef IS_X8664
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      /* Number is too big for Fixnum. Use Bignum. */
      return Bignum::from(state, (native_int)num);
    }
#endif
    return (Fixnum*)APPLY_FIXNUM_TAG(num);
  }

  Integer* Integer::from(STATE, unsigned int num) {
#ifndef IS_X8664
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, (unsigned long)num);
    }
#endif
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, unsigned long num) {
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, long num) {
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, long long num) {
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, unsigned long long num) {
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  // Adapted from MRI.
  static const signed char digit_value[] = {
    /*     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
    /*0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-1,-1,-2,-1,-1,
    /*1*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*2*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*3*/  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
    /*4*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
    /*5*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,'_',
    /*6*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
    /*7*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
    /*8*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*9*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*a*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*b*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*c*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*d*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*e*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*f*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  };

  static const int digit_bits[] = {
    1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6
  };

  Integer* Integer::from_cstr(STATE, const char* str, const char* end,
                              int base, Object* strict)
  {
    if(base == 1 || base > 36) return nil<Integer>();

    // Skip any combination of leading whitespace and underscores.  Leading
    // whitespace is OK in strict mode, but underscores are not.
    while(isspace(*str) || *str == '_') {
      if(*str == '_') {
        if(CBOOL(strict)) {
          return nil<Integer>();
        } else {
          return Fixnum::from(0);
        }
      }

      str++;
    }

    bool negative = false;

    if(*str == '-') {
      str++;
      negative = true;
    } else if(*str == '+') {
      str++;
    }

    int detected_base = 0;
    const char* str_start = str;

    /* Try to detect a base prefix. We have to do this even though we might
     * have been told the base, we have to know if we should discard the bytes
     * that make up the prefix if it's redundant with the passed in base.
     *
     * For example, if base == 16 and str == "0xa", we return 10.  But if base
     * == 10 and str == "0xa", we fail because we rewind and try to process 0x
     * as part of the base 10 string.
     */
    if(*str == '0') {
      str++;
      switch(*str++) {
      case 'b': case 'B':
        detected_base = 2;
        break;
      case 'o': case 'O':
        detected_base = 8;
        break;
      case 'd': case 'D':
        detected_base = 10;
        break;
      case 'x': case 'X':
        detected_base = 16;
        break;
      default:
        // If passed "017" and a base of 0, that is octal 15.  Otherwise, it
        // is whatever those digits would be in the specified base.
        str--;
        detected_base = 8;
      }
    }

    // If base is less than 0, then it's just a hint for how to process it
    // if there is no base detected.
    if(base < 0) {
      if(detected_base == 0) {
        // Ok, no detected because, use the base hint and start over.
        base = -base;
        str = str_start;
      } else {
        base = detected_base;
      }

    // If 0 was passed in as the base, we use the detected base.
    } else if(base == 0) {

      // Default to 10 if there is no input and no detected base.
      if(detected_base == 0) {
        base = 10;
        str = str_start;

      } else {
        base = detected_base;
      }

    // If the passed in base and the detected base contradict each other, then
    // rewind and process the whole string as digits of the passed in base.
    } else if(base != detected_base) {
      // Rewind the stream and try and consume the prefix as digits in the
      // number.
      str = str_start;
    }

    int max_digits = DIGIT_BIT / digit_bits[base];
    int count = 0;

    int digit;
    mp_digit shift = base, value = 0;
    mp_int a = { 0 };

    while(str < end) {
      digit = digit_value[int(*str++)];

      if(digit >= 0 && digit < base) {
        if(++count <= max_digits) {
          value = value * base + digit;
        } else {
          if(!mp_isinitialized(&a)) {
            mp_init_set_long(XST, &a, value);
            for(int i = 0; i < max_digits - 1; i++) {
              shift *= base;
            }
          } else {
            mp_mul_d(XST, &a, shift, &a);
            mp_add_d(XST, &a, value, &a);
          }

          value = digit;
          count = 1;
        }

        continue;
      }

      // An underscore is valid iff it is followed by a valid character for
      // this base.
      if(digit == '_') {
        if(*str == '_') goto error_check;

        continue;
      }

      if(digit >= base) goto error_check;

      // Consume any whitespace characters.
      if(digit < -1) {
        while(digit_value[int(*str++)] < -1) /* skip whitespace */ ;

        goto error_check;
      }

      // Done parsing.
      break;
    }

error_check:

    if(*str && CBOOL(strict)) {
      if(mp_isinitialized(&a)) mp_clear(&a);
      return nil<Integer>();
    }

    if(!mp_isinitialized(&a)) {
      if(value < FIXNUM_MAX) {
        Fixnum* result = Fixnum::from(value);
        if(negative) {
          return result->neg(state);
        } else {
          return result;
        }
      }

      mp_init_set_long(XST, &a, value);
    } else {
      shift = base;
      for(int i = 0; i < count - 1; i++) {
        shift *= base;
      }

      mp_mul_d(XST, &a, shift, &a);
      mp_add_d(XST, &a, value, &a);
    }

    if(negative) {
      mp_neg(XST, &a, &a);
    }

    Integer* result = Bignum::from(state, &a);
    mp_clear(&a);

    return result;
  }
}
<commit_msg>Fixed parsing integers.<commit_after>#include "builtin/bignum.hpp"
#include "builtin/class.hpp"
#include "builtin/fixnum.hpp"
#include "builtin/float.hpp"
#include "builtin/integer.hpp"
#include "object_utils.hpp"
#include "ontology.hpp"
#include "configuration.hpp"

#include <tommath.h>

#define XST ((void*)state)

namespace rubinius {

  void Numeric::init(STATE) {
    GO(numeric).set(ontology::new_class(state, "Numeric"));
    // We inherit from this type in for example Rational
    // and that class shouldn't have NumericType set since
    // that can cause problems.
    G(numeric)->set_object_type(state, ObjectType);
  }

  void Integer::init(STATE) {
    GO(integer).set(ontology::new_class(state, "Integer", G(numeric)));
    G(integer)->set_object_type(state, IntegerType);
  }

  native_int Integer::bignum_to_native() {
    return as<Bignum>(this)->to_native();
  }

  unsigned int Integer::to_uint() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_uint();
    }

    return as<Bignum>(this)->to_uint();
  }

  long Integer::to_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_long();
    }

    return as<Bignum>(this)->to_long();
  }

  unsigned long Integer::to_ulong() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_ulong();
    }

    return as<Bignum>(this)->to_ulong();
  }

  long long Integer::to_long_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_long_long();
    }

    return as<Bignum>(this)->to_long_long();
  }

  unsigned long long Integer::to_ulong_long() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->to_ulong_long();
    }

    return as<Bignum>(this)->to_ulong_long();
  }

  bool Integer::positive_p() {
    if(fixnum_p()) {
      return (force_as<Fixnum>(this))->positive_p();
    }

    return as<Bignum>(this)->positive_p();
  }

  Integer* Integer::from(STATE, int num) {
#ifndef IS_X8664
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      /* Number is too big for Fixnum. Use Bignum. */
      return Bignum::from(state, (native_int)num);
    }
#endif
    return (Fixnum*)APPLY_FIXNUM_TAG(num);
  }

  Integer* Integer::from(STATE, unsigned int num) {
#ifndef IS_X8664
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, (unsigned long)num);
    }
#endif
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, unsigned long num) {
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, long num) {
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, long long num) {
    if(num > FIXNUM_MAX || num < FIXNUM_MIN) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  Integer* Integer::from(STATE, unsigned long long num) {
    if(num > FIXNUM_MAX) {
      return Bignum::from(state, num);
    }
    return (Fixnum*)APPLY_FIXNUM_TAG((native_int)num);
  }

  // Adapted from MRI.
  static const signed char digit_value[] = {
    /*     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f */
    /*0*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-2,-1,-1,-2,-1,-1,
    /*1*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*2*/ -2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*3*/  0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1,
    /*4*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
    /*5*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,'_',
    /*6*/ -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,
    /*7*/ 25,26,27,28,29,30,31,32,33,34,35,-1,-1,-1,-1,-1,
    /*8*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*9*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*a*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*b*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*c*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*d*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*e*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
    /*f*/ -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,
  };

  static const int digit_bits[] = {
    1, 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5,
    5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6
  };

  Integer* Integer::from_cstr(STATE, const char* str, const char* end,
                              int base, Object* strict)
  {
    if(base == 1 || base > 36) return nil<Integer>();

    // Skip any combination of leading whitespace and underscores.  Leading
    // whitespace is OK in strict mode, but underscores are not.
    while(isspace(*str) || *str == '_') {
      if(*str == '_') {
        if(CBOOL(strict)) {
          return nil<Integer>();
        } else {
          return Fixnum::from(0);
        }
      }

      str++;
    }

    bool negative = false;

    if(*str == '-') {
      str++;
      negative = true;
    } else if(*str == '+') {
      str++;
    }

    int detected_base = 0;
    const char* str_start = str;

    /* Try to detect a base prefix. We have to do this even though we might
     * have been told the base, we have to know if we should discard the bytes
     * that make up the prefix if it's redundant with the passed in base.
     *
     * For example, if base == 16 and str == "0xa", we return 10.  But if base
     * == 10 and str == "0xa", we fail because we rewind and try to process 0x
     * as part of the base 10 string.
     */
    if(*str == '0') {
      str++;
      switch(*str++) {
      case 'b': case 'B':
        detected_base = 2;
        break;
      case 'o': case 'O':
        detected_base = 8;
        break;
      case 'd': case 'D':
        detected_base = 10;
        break;
      case 'x': case 'X':
        detected_base = 16;
        break;
      default:
        // If passed "017" and a base of 0, that is octal 15.  Otherwise, it
        // is whatever those digits would be in the specified base.
        str--;
        detected_base = 8;
      }
    }

    // If base is less than 0, then it's just a hint for how to process it
    // if there is no base detected.
    if(base < 0) {
      if(detected_base == 0) {
        // Ok, no detected because, use the base hint and start over.
        base = -base;
        str = str_start;
      } else {
        base = detected_base;
      }

    // If 0 was passed in as the base, we use the detected base.
    } else if(base == 0) {

      // Default to 10 if there is no input and no detected base.
      if(detected_base == 0) {
        base = 10;
        str = str_start;

      } else {
        base = detected_base;
      }

    // If the passed in base and the detected base contradict each other, then
    // rewind and process the whole string as digits of the passed in base.
    } else if(base != detected_base) {
      // Rewind the stream and try and consume the prefix as digits in the
      // number.
      str = str_start;
    }

    int max_digits = DIGIT_BIT / digit_bits[base];
    int count = 0;

    int digit = 0;
    mp_digit shift = base, value = 0;
    mp_int a = { 0 };

    for( ; str < end; str++) {
      digit = digit_value[int(*str)];

      if(digit >= 0 && digit < base) {
        if(++count <= max_digits) {
          value = value * base + digit;
        } else {
          if(!mp_isinitialized(&a)) {
            mp_init_set_long(XST, &a, value);
            for(int i = 0; i < max_digits - 1; i++) {
              shift *= base;
            }
          } else {
            mp_mul_d(XST, &a, shift, &a);
            mp_add_d(XST, &a, value, &a);
          }

          value = digit;
          count = 1;
        }

        continue;
      }

      // An underscore is valid iff it is followed by a valid character for
      // this base.
      if(*str == '_') {
        if(!*(str + 1) || *(str + 1) == '_') goto error_check;

        continue;
      }

      if(digit >= base) goto error_check;

      // Consume any whitespace characters.
      if(digit < -1) {
        while(digit_value[int(*++str)] < -1) /* skip whitespace */ ;

        goto error_check;
      }

      // Done parsing.
      break;
    }

error_check:

    if(str < end && CBOOL(strict)) {
      if(mp_isinitialized(&a)) mp_clear(&a);
      return nil<Integer>();
    }

    if(!mp_isinitialized(&a)) {
      if(value < FIXNUM_MAX) {
        Fixnum* result = Fixnum::from(value);
        if(negative) {
          return result->neg(state);
        } else {
          return result;
        }
      }

      mp_init_set_long(XST, &a, value);
    } else {
      shift = base;
      for(int i = 0; i < count - 1; i++) {
        shift *= base;
      }

      mp_mul_d(XST, &a, shift, &a);
      mp_add_d(XST, &a, value, &a);
    }

    if(negative) {
      mp_neg(XST, &a, &a);
    }

    Integer* result = Bignum::from(state, &a);
    mp_clear(&a);

    return result;
  }
}
<|endoftext|>


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

#include "common/sg/SceneGraph.h"
#include "common/sg/Renderer.h"
#include "common/sg/importer/Importer.h"
#include "ospcommon/FileName.h"

#include "sg/geometry/TriangleMesh.h"

#include "widgets/imguiViewerSg.h"

#include <sstream>

using namespace ospcommon;
using namespace ospray;

std::vector<std::string> files;
std::string initialRendererType;
bool addPlane = true;
bool debug = false;
bool fullscreen = false;

void parseCommandLine(int ac, const char **&av)
{
  for (int i = 1; i < ac; i++) {
    const std::string arg = av[i];
    if (arg == "-np" || arg == "--no-plane") {
      addPlane = false;
    } else if (arg == "-d" || arg == "--debug") {
      debug = true;
    } else if (arg == "-r" || arg == "--renderer") {
      initialRendererType = av[++i];
    } else if (arg == "-m" || arg == "--module") {
      ospLoadModule(av[++i]);
    } else if (arg == "--fullscreen") {
      fullscreen = true;
    } else if (arg[0] != '-') {
      files.push_back(av[i]);
    }
  }
}

//parse command line arguments containing the format:
//  -nodeName:...:nodeName=value,value,value
void parseCommandLineSG(int ac, const char **&av, sg::NodeH root)
{
  for(int i=1;i < ac; i++)
  {
    std::string arg(av[i]);
    size_t f;
    std::string value("");
    if (arg.size() < 2 || arg[0] != '-')
      continue;
    while ( (f = arg.find(":")) != std::string::npos || (f = arg.find(",")) != std::string::npos)
      arg[f]=' ';
    f = arg.find("=");
    if (f != std::string::npos)
    {
      value = arg.substr(f+1,arg.size());
    }
    if (value != "")
    {
      std::stringstream ss;
      ss << arg.substr(1,f-1);
      std::string child;
      sg::NodeH node = root;
      while (ss >> child)
      {
        node = node->childRecursive(child);
      }
      //Carson: TODO: reimplement with a way of determining type of node value
      //  currently relies on exception on value cast
      try
      {
        node->valueAs<std::string>();
        node->setValue(value);
      } catch(...) {};
      try
      {
        std::stringstream vals(value);
        float x;
        vals >> x;
        node->valueAs<float>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x;
        vals >> x;
        node->valueAs<int>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        bool x;
        vals >> x;
        node->valueAs<bool>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        float x,y,z;
        vals >> x >> y >> z;
        node->valueAs<ospcommon::vec3f>();
        node->setValue(ospcommon::vec3f(x,y,z));
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x,y;
        vals >> x >> y;
        node->valueAs<ospcommon::vec2i>();
        node->setValue(ospcommon::vec2i(x,y));
      } catch(...) {}
    }
  }
}

void addPlaneToScene(sg::NodeH &world)
{
  //add plane
  auto bbox = world->bounds();

  osp::vec3f *vertices = new osp::vec3f[4];
  float ps = bbox.upper.x*3.f;
  float py = bbox.lower.z-0.01f;

  py = bbox.lower.y-0.01f;
  vertices[0] = osp::vec3f{-ps, py, -ps};
  vertices[1] = osp::vec3f{-ps, py, ps};
  vertices[2] = osp::vec3f{ps, py, -ps};
  vertices[3] = osp::vec3f{ps, py, ps};
  auto position = std::make_shared<sg::DataArray3f>((vec3f*)&vertices[0],
                                                    size_t(4),
                                                    false);
  osp::vec3i *triangles = new osp::vec3i[2];
  triangles[0] = osp::vec3i{0,1,2};
  triangles[1] = osp::vec3i{1,2,3};
  auto index = std::make_shared<sg::DataArray3i>((vec3i*)&triangles[0],
                                                 size_t(2),
                                                 false);
  auto plane = sg::createNode("plane", "InstanceGroup");
  auto mesh  = sg::createNode("mesh", "TriangleMesh");
  std::shared_ptr<sg::TriangleMesh> sg_plane =
    std::static_pointer_cast<sg::TriangleMesh>(mesh.get());
  sg_plane->vertex = position;
  sg_plane->index = index;
  auto planeMaterial = mesh["material"];
  planeMaterial["Kd"]->setValue(vec3f(0.5f));
  planeMaterial["Ks"]->setValue(vec3f(0.6f));
  planeMaterial["Ns"]->setValue(2.f);
  plane += mesh;
  world += plane;
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);

#ifdef _WIN32
  // TODO: Why do we not have the sg symbols already available for us
  // since we link against it?
  loadLibrary("ospray_sg");
#endif

  ospray::imgui3D::init(&ac,av);

  parseCommandLine(ac, av);

  auto renderer = sg::createNode("renderer", "Renderer");
  renderer["shadowsEnabled"]->setValue(true);
  renderer["aoSamples"]->setValue(1);
  renderer["camera"]["fovy"]->setValue(60.f);

  if (!initialRendererType.empty())
    renderer["rendererType"]->setValue(initialRendererType);

  auto lights = renderer["lights"];

  auto sun =  sg::createNode("sun", "DirectionalLight");
  sun["color"]->setValue(vec3f(1.f,232.f/255.f,166.f/255.f));
  sun["direction"]->setValue(vec3f(0.462f,-1.f,-.1f));
  sun["intensity"]->setValue(1.5f);
  lights += sun;

  auto bounce = sg::createNode("bounce", "DirectionalLight");
  bounce["color"]->setValue(vec3f(127.f/255.f,178.f/255.f,255.f/255.f));
  bounce["direction"]->setValue(vec3f(-.93,-.54f,-.605f));
  bounce["intensity"]->setValue(0.25f);
  lights += bounce;

  auto ambient = sg::createNode("ambient", "AmbientLight");
  ambient["intensity"]->setValue(0.9f);
  ambient["color"]->setValue(vec3f(174.f/255.f,218.f/255.f,255.f/255.f));
  lights += ambient;

  auto world = renderer["world"];

  for (auto file : files) {
    FileName fn = file;
    auto importerNode = sg::createNode(fn.name(), "Importer");
    importerNode["fileName"]->setValue(fn.str());
    world += importerNode;
  }

  parseCommandLineSG(ac, av, renderer);

  if (debug) {
    renderer->traverse("verify");
    renderer->traverse("print");
  }

  renderer->traverse("commit");

  ospray::ImGuiViewerSg window(renderer);
  if (addPlane) addPlaneToScene(world);
  window.create("OSPRay Example Viewer App", fullscreen);

  ospray::imgui3D::run();
}
<commit_msg>experimenting with display wall<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "common/sg/SceneGraph.h"
#include "common/sg/Renderer.h"
#include "common/sg/importer/Importer.h"
#include "ospcommon/FileName.h"

#include "sg/geometry/TriangleMesh.h"

#include "widgets/imguiViewerSg.h"

#include <sstream>

using namespace ospcommon;
using namespace ospray;

std::vector<std::string> files;
std::string initialRendererType;
bool addPlane = true;
bool debug = false;
bool fullscreen = false;

void parseCommandLine(int ac, const char **&av)
{
  for (int i = 1; i < ac; i++) {
    const std::string arg = av[i];
    if (arg == "-np" || arg == "--no-plane") {
      addPlane = false;
    } else if (arg == "-d" || arg == "--debug") {
      debug = true;
    } else if (arg == "-r" || arg == "--renderer") {
      initialRendererType = av[++i];
    } else if (arg == "-m" || arg == "--module") {
      ospLoadModule(av[++i]);
    } else if (arg == "--fullscreen") {
      fullscreen = true;
    } else if (arg[0] != '-') {
      files.push_back(av[i]);
    }
  }
}

//parse command line arguments containing the format:
//  -nodeName:...:nodeName=value,value,value
void parseCommandLineSG(int ac, const char **&av, sg::NodeH root)
{
  for(int i=1;i < ac; i++)
  {
    std::string arg(av[i]);
    size_t f;
    std::string value("");
    if (arg.size() < 2 || arg[0] != '-')
      continue;
    while ( (f = arg.find(":")) != std::string::npos || (f = arg.find(",")) != std::string::npos)
      arg[f]=' ';
    f = arg.find("=");
    if (f != std::string::npos)
    {
      value = arg.substr(f+1,arg.size());
    }
    if (value != "")
    {
      std::stringstream ss;
      ss << arg.substr(1,f-1);
      std::string child;
      sg::NodeH node = root;
      while (ss >> child)
      {
        node = node->childRecursive(child);
      }
      //Carson: TODO: reimplement with a way of determining type of node value
      //  currently relies on exception on value cast
      try
      {
        node->valueAs<std::string>();
        node->setValue(value);
      } catch(...) {};
      try
      {
        std::stringstream vals(value);
        float x;
        vals >> x;
        node->valueAs<float>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x;
        vals >> x;
        node->valueAs<int>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        bool x;
        vals >> x;
        node->valueAs<bool>();
        node->setValue(x);
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        float x,y,z;
        vals >> x >> y >> z;
        node->valueAs<ospcommon::vec3f>();
        node->setValue(ospcommon::vec3f(x,y,z));
      } catch(...) {}
      try
      {
        std::stringstream vals(value);
        int x,y;
        vals >> x >> y;
        node->valueAs<ospcommon::vec2i>();
        node->setValue(ospcommon::vec2i(x,y));
      } catch(...) {}
    }
  }
}

void addPlaneToScene(sg::NodeH &world)
{
  //add plane
  auto bbox = world->bounds();

  osp::vec3f *vertices = new osp::vec3f[4];
  float ps = bbox.upper.x*3.f;
  float py = bbox.lower.z-0.01f;

  py = bbox.lower.y-0.01f;
  vertices[0] = osp::vec3f{-ps, py, -ps};
  vertices[1] = osp::vec3f{-ps, py, ps};
  vertices[2] = osp::vec3f{ps, py, -ps};
  vertices[3] = osp::vec3f{ps, py, ps};
  auto position = std::make_shared<sg::DataArray3f>((vec3f*)&vertices[0],
                                                    size_t(4),
                                                    false);
  osp::vec3i *triangles = new osp::vec3i[2];
  triangles[0] = osp::vec3i{0,1,2};
  triangles[1] = osp::vec3i{1,2,3};
  auto index = std::make_shared<sg::DataArray3i>((vec3i*)&triangles[0],
                                                 size_t(2),
                                                 false);
  auto plane = sg::createNode("plane", "InstanceGroup");
  auto mesh  = sg::createNode("mesh", "TriangleMesh");
  std::shared_ptr<sg::TriangleMesh> sg_plane =
    std::static_pointer_cast<sg::TriangleMesh>(mesh.get());
  sg_plane->vertex = position;
  sg_plane->index = index;
  auto planeMaterial = mesh["material"];
  planeMaterial["Kd"]->setValue(vec3f(0.5f));
  planeMaterial["Ks"]->setValue(vec3f(0.6f));
  planeMaterial["Ns"]->setValue(2.f);
  plane += mesh;
  world += plane;
}

int main(int ac, const char **av)
{
  ospInit(&ac,av);

#ifdef _WIN32
  // TODO: Why do we not have the sg symbols already available for us
  // since we link against it?
  loadLibrary("ospray_sg");
#endif

  ospray::imgui3D::init(&ac,av);

  parseCommandLine(ac, av);

  auto renderer = sg::createNode("renderer", "Renderer");

  renderer["shadowsEnabled"]->setValue(true);
  renderer["aoSamples"]->setValue(1);
  renderer["camera"]["fovy"]->setValue(60.f);

  if (!initialRendererType.empty())
    renderer["rendererType"]->setValue(initialRendererType);

  auto lights = renderer["lights"];

  auto sun =  sg::createNode("sun", "DirectionalLight");
  sun["color"]->setValue(vec3f(1.f,232.f/255.f,166.f/255.f));
  sun["direction"]->setValue(vec3f(0.462f,-1.f,-.1f));
  sun["intensity"]->setValue(1.5f);
  lights += sun;

  auto bounce = sg::createNode("bounce", "DirectionalLight");
  bounce["color"]->setValue(vec3f(127.f/255.f,178.f/255.f,255.f/255.f));
  bounce["direction"]->setValue(vec3f(-.93,-.54f,-.605f));
  bounce["intensity"]->setValue(0.25f);
  lights += bounce;

  auto ambient = sg::createNode("ambient", "AmbientLight");
  ambient["intensity"]->setValue(0.9f);
  ambient["color"]->setValue(vec3f(174.f/255.f,218.f/255.f,255.f/255.f));
  lights += ambient;

  auto world = renderer["world"];

  for (auto file : files) {
    FileName fn = file;
    auto importerNode = sg::createNode(fn.name(), "Importer");
    importerNode["fileName"]->setValue(fn.str());
    world += importerNode;
  }

  parseCommandLineSG(ac, av, renderer);

  if (debug) {
    renderer->traverse("verify");
    renderer->traverse("print");
  }

  renderer->traverse("commit");

#ifdef DW
  auto dwRenderer = sg::createNode("displayWallRenderer", "Renderer");
  dwRenderer["lights"] = renderer["lights"];
  dwRenderer["shadowsEnabled"] = renderer["shadowsEnabled"];
  dwRenderer["aoSamples"] = renderer["aoSamples"]->setValue(1);
  dwRenderer["camera"] = renderer["camera"];
  dwRenderer["world"] = renderer["world"];
  dwRenderer->traverse("commit");
#endif

  ospray::ImGuiViewerSg window(renderer);
  if (addPlane) addPlaneToScene(world);
  window.create("OSPRay Example Viewer App", fullscreen);

  ospray::imgui3D::run();
}
<|endoftext|>


<commit_before>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "nntpresource.h"
#include "nntpcollectionattribute.h"
#include "configdialog.h"
#include "settings.h"

#include <libakonadi/collectionattributefactory.h>
#include <libakonadi/collectionmodifyjob.h>
#include <libakonadi/itemappendjob.h>
#include <libakonadi/itemstorejob.h>
#include <libakonadi/session.h>

#include <kmime/kmime_message.h>
#include <kmime/kmime_newsarticle.h>
#include <kmime/kmime_util.h>

#include <QDate>
#include <QDir>
#include <QInputDialog>
#include <QLineEdit>

#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<KMime::Message> MessagePtr;

using namespace Akonadi;

NntpResource::NntpResource(const QString & id)
  : ResourceBase( id )
{
  CollectionAttributeFactory::registerAttribute<NntpCollectionAttribute>();
}

NntpResource::~ NntpResource()
{
}

bool NntpResource::retrieveItem(const Akonadi::Item& item, const QStringList &parts)
{
  Q_UNUSED( parts );
  KIO::Job* job = KIO::storedGet( KUrl( item.reference().remoteId() ), KIO::NoReload, KIO::HideProgressInfo );
  setupKioJob( job );
  connect( job, SIGNAL( result(KJob*) ), SLOT( fetchArticleResult(KJob*) ) );
  return true;
}

void NntpResource::retrieveCollections()
{
  remoteCollections.clear();
  Collection rootCollection;
  rootCollection.setParent( Collection::root() );
  rootCollection.setRemoteId( baseUrl().url() );
  rootCollection.setName( Settings::self()->name() );
  rootCollection.setCachePolicyId( 1 );
  QStringList contentTypes;
  contentTypes << Collection::collectionMimeType();
  rootCollection.setContentTypes( contentTypes );
  remoteCollections << rootCollection;

  KUrl url = baseUrl();
  QDate lastList = settings()->value( "General/LastGroupList" ).toDate();
  if ( lastList.isValid() ) {
    mIncremental = true;
    url.addQueryItem( "since",  QString("%1%2%3 000000")
        .arg( lastList.year() % 100, 2, 10, QChar( '0' ) )
        .arg( lastList.month(), 2, 10, QChar( '0' ) )
        .arg( lastList.day(), 2, 10, QChar( '0' ) ) );
  } else {
    mIncremental = false;
  }

  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
  setupKioJob( job );
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
           SLOT(listGroups(KIO::Job*, const KIO::UDSEntryList&)) );
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupsResult(KJob*) ) );
}

void NntpResource::retrieveItems(const Akonadi::Collection & col, const QStringList &parts)
{
  Q_UNUSED( parts );
  KUrl url = baseUrl();
  url.setPath( col.remoteId() );

  NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>();
  if ( attr && attr->lastArticle() > 0 )
    url.addQueryItem( "first", QString::number( attr->lastArticle() + 1 ) );
  else
    url.addQueryItem( "max", QString::number( Settings::self()->maxDownload() ) );

  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
  setupKioJob( job );
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
           SLOT(listGroup(KIO::Job*, const KIO::UDSEntryList&)) );
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupResult(KJob*) ) );
}

void NntpResource::listGroups(KIO::Job * job, const KIO::UDSEntryList & list)
{
  Q_UNUSED( job );
  QString name;
  QStringList contentTypes;
  contentTypes << "message/news";
  for( KIO::UDSEntryList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) {
    name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
    if ( name.isEmpty() )
      continue;

    Collection c;
    c.setRemoteId( name );
    c.setContentTypes( contentTypes );

    if ( Settings::self()->flatHierarchy() ) {
      c.setName( name );
      c.setParentRemoteId( baseUrl().url() );
    } else {
      const QStringList path = name.split( '.' );
      Q_ASSERT( !path.isEmpty() );
      c.setName( path.last() );
      c.setParentRemoteId( findParent( path ) );
    }

    remoteCollections << c;
  }
}

void NntpResource::listGroupsResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
    return;
  } else {
    settings()->setValue( "General/LastGroupList", QDate::currentDate() );
  }
  if ( mIncremental )
    collectionsRetrievedIncremental( remoteCollections, Collection::List() );
  else
    collectionsRetrieved( remoteCollections );
}

void NntpResource::listGroup(KIO::Job * job, const KIO::UDSEntryList & list)
{
  Q_UNUSED( job );
  foreach ( const KIO::UDSEntry &entry, list ) {
    KUrl url = baseUrl();
    url.setPath( currentCollection().remoteId() + "/" + entry.stringValue( KIO::UDSEntry::UDS_NAME ) );
    DataReference ref( -1, url.url() );
    Item item( ref );
    item.setMimeType( "message/news" );

    KMime::NewsArticle *art = new KMime::NewsArticle();
    foreach ( uint field, entry.listFields() ) {
      if ( field >= KIO::UDSEntry::UDS_EXTRA && field <= KIO::UDSEntry::UDS_EXTRA_END ) {
        const QString value = entry.stringValue( field );
        int pos = value.indexOf( ':' );
        if ( pos >= value.length() - 1 )
          continue; // value is empty
        const QString hdrName = value.left( pos );
        const QString hdrValue = value.right( value.length() - ( hdrName.length() + 2 ) );

        if ( hdrName == "Subject" ) {
          art->subject()->from7BitString( hdrValue.toLatin1() );
          if ( art->subject()->isEmpty() )
            art->subject()->fromUnicodeString( i18n("no subject"), art->defaultCharset() );
        } else if ( hdrName == "From" ) {
          art->from()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Date" ) {
          art->date()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Message-ID" ) {
          art->messageID()->from7BitString( hdrValue.simplified().toLatin1() );
        } else if ( hdrName == "References" ) {
          if( !hdrValue.isEmpty() )
            art->references()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Lines" ) {
          art->lines()->setNumberOfLines( hdrValue.toInt() );
        } else {
          // optional extra headers
          art->setHeader( new KMime::Headers::Generic( hdrName.toLatin1(), art, hdrValue.toLatin1() ) );
        }
      }
    }

    item.setPayload( MessagePtr( art ) );
    ItemAppendJob *append = new ItemAppendJob( item, currentCollection(), session() );
    // TODO: check error
  }
}

void NntpResource::listGroupResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
  } else {
    // store last serial number
    Collection col = currentCollection();
    NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>( true );
    KIO::Job *j = static_cast<KIO::Job*>( job );
    if ( j->metaData().contains( "LastSerialNumber" ) )
      attr->setLastArticle( j->metaData().value("LastSerialNumber").toInt() );
    CollectionModifyJob *modify = new CollectionModifyJob( col, session() );
    modify->setAttribute( attr );
    // TODO: check result signal
  }

  itemsRetrieved();
}

KUrl NntpResource::baseUrl() const
{
  KUrl url;
 if ( Settings::self()->encryption() == Settings::SSL )
    url.setProtocol( "nntps" );
  else
    url.setProtocol( "nntp" );
  url.setHost( Settings::self()->server() );
  url.setPort( Settings::self()->port() );
  if ( Settings::self()->requiresAuthentication() ) {
    url.setUser( Settings::self()->userName() );
    url.setPass( Settings::self()->password() );
  }
  return url;
}

void NntpResource::fetchArticleResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
    return;
  }
  KIO::StoredTransferJob *j = static_cast<KIO::StoredTransferJob*>( job );
  KMime::Message *msg = new KMime::Message();
  msg->setContent( KMime::CRLFtoLF( j->data() ) );
  msg->parse();
  Item item = currentItem();
  item.setMimeType( "message/news" );
  item.setPayload( MessagePtr( msg ) );
  itemRetrieved( item );
}

void NntpResource::configure()
{
  ConfigDialog dlg;
  dlg.exec();
}

void NntpResource::setupKioJob(KIO::Job * job) const
{
  Q_ASSERT( job );
  if ( Settings::self()->encryption() == Settings::TLS )
    job->addMetaData( "tls", "on" );
  else
    job->addMetaData( "tls", "off" );
  // TODO connect percent and status message signals to something
}

QString NntpResource::findParent(const QStringList & _path)
{
  QStringList path = _path;
  path.removeLast();
  if ( path.isEmpty() )
    return baseUrl().url();
  QString rid = path.join( "." );
  foreach ( const Collection col, remoteCollections )
    if ( col.remoteId() == rid )
      return col.remoteId();
  Collection parent;
  parent.setRemoteId( rid );
  QStringList ct;
  ct << Collection::collectionMimeType();
  parent.setContentTypes( ct );
  parent.setParentRemoteId( findParent( path ) );
  parent.setName( path.last() );
  remoteCollections << parent;
  return parent.remoteId();
}

void NntpResource::collectionChanged(const Akonadi::Collection & collection)
{
  kDebug() << collection.remoteId() << collection.name();
  if ( collection.remoteId() == baseUrl().url() )
    Settings::self()->setName( collection.name() );
}

#include "nntpresource.moc"
<commit_msg>- fix name changes - skip structural collections when syncing<commit_after>/*
    Copyright (c) 2007 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "nntpresource.h"
#include "nntpcollectionattribute.h"
#include "configdialog.h"
#include "settings.h"

#include <libakonadi/collectionattributefactory.h>
#include <libakonadi/collectionmodifyjob.h>
#include <libakonadi/itemappendjob.h>
#include <libakonadi/itemstorejob.h>
#include <libakonadi/session.h>
#include <libakonadi/changerecorder.h>

#include <kmime/kmime_message.h>
#include <kmime/kmime_newsarticle.h>
#include <kmime/kmime_util.h>

#include <QDate>
#include <QDir>
#include <QInputDialog>
#include <QLineEdit>

#include <boost/shared_ptr.hpp>
typedef boost::shared_ptr<KMime::Message> MessagePtr;

using namespace Akonadi;

NntpResource::NntpResource(const QString & id)
  : ResourceBase( id )
{
  CollectionAttributeFactory::registerAttribute<NntpCollectionAttribute>();
  monitor()->fetchCollection( true );
}

NntpResource::~ NntpResource()
{
}

bool NntpResource::retrieveItem(const Akonadi::Item& item, const QStringList &parts)
{
  Q_UNUSED( parts );
  KIO::Job* job = KIO::storedGet( KUrl( item.reference().remoteId() ), KIO::NoReload, KIO::HideProgressInfo );
  setupKioJob( job );
  connect( job, SIGNAL( result(KJob*) ), SLOT( fetchArticleResult(KJob*) ) );
  return true;
}

void NntpResource::retrieveCollections()
{
  remoteCollections.clear();
  Collection rootCollection;
  rootCollection.setParent( Collection::root() );
  rootCollection.setRemoteId( baseUrl().url() );
  rootCollection.setName( Settings::self()->name() );
  rootCollection.setCachePolicyId( 1 );
  QStringList contentTypes;
  contentTypes << Collection::collectionMimeType();
  rootCollection.setContentTypes( contentTypes );
  remoteCollections << rootCollection;

  KUrl url = baseUrl();
  QDate lastList = settings()->value( "General/LastGroupList" ).toDate();
  if ( lastList.isValid() ) {
    mIncremental = true;
    url.addQueryItem( "since",  QString("%1%2%3 000000")
        .arg( lastList.year() % 100, 2, 10, QChar( '0' ) )
        .arg( lastList.month(), 2, 10, QChar( '0' ) )
        .arg( lastList.day(), 2, 10, QChar( '0' ) ) );
  } else {
    mIncremental = false;
  }

  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
  setupKioJob( job );
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
           SLOT(listGroups(KIO::Job*, const KIO::UDSEntryList&)) );
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupsResult(KJob*) ) );
}

void NntpResource::retrieveItems(const Akonadi::Collection & col, const QStringList &parts)
{
  Q_UNUSED( parts );
  if ( !(col.contentTypes().count() == 1 && col.contentTypes().first() == "message/news" ) ) {
    // not a newsgroup, skip it
    itemsRetrieved();
    return;
  }

  KUrl url = baseUrl();
  url.setPath( col.remoteId() );

  NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>();
  if ( attr && attr->lastArticle() > 0 )
    url.addQueryItem( "first", QString::number( attr->lastArticle() + 1 ) );
  else
    url.addQueryItem( "max", QString::number( Settings::self()->maxDownload() ) );

  KIO::Job* job = KIO::listDir( url, KIO::HideProgressInfo, true );
  setupKioJob( job );
  connect( job, SIGNAL(entries(KIO::Job*, const KIO::UDSEntryList&)),
           SLOT(listGroup(KIO::Job*, const KIO::UDSEntryList&)) );
  connect( job, SIGNAL( result(KJob*) ), SLOT( listGroupResult(KJob*) ) );
}

void NntpResource::listGroups(KIO::Job * job, const KIO::UDSEntryList & list)
{
  Q_UNUSED( job );
  QString name;
  QStringList contentTypes;
  contentTypes << "message/news";
  for( KIO::UDSEntryList::ConstIterator it = list.constBegin(); it != list.constEnd(); ++it ) {
    name = (*it).stringValue( KIO::UDSEntry::UDS_NAME );
    if ( name.isEmpty() )
      continue;

    Collection c;
    c.setRemoteId( name );
    c.setContentTypes( contentTypes );

    if ( Settings::self()->flatHierarchy() ) {
      c.setName( name );
      c.setParentRemoteId( baseUrl().url() );
    } else {
      const QStringList path = name.split( '.' );
      Q_ASSERT( !path.isEmpty() );
      c.setName( path.last() );
      c.setParentRemoteId( findParent( path ) );
    }

    remoteCollections << c;
  }
}

void NntpResource::listGroupsResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
    return;
  } else {
    settings()->setValue( "General/LastGroupList", QDate::currentDate() );
  }
  if ( mIncremental )
    collectionsRetrievedIncremental( remoteCollections, Collection::List() );
  else
    collectionsRetrieved( remoteCollections );
}

void NntpResource::listGroup(KIO::Job * job, const KIO::UDSEntryList & list)
{
  Q_UNUSED( job );
  foreach ( const KIO::UDSEntry &entry, list ) {
    KUrl url = baseUrl();
    url.setPath( currentCollection().remoteId() + "/" + entry.stringValue( KIO::UDSEntry::UDS_NAME ) );
    DataReference ref( -1, url.url() );
    Item item( ref );
    item.setMimeType( "message/news" );

    KMime::NewsArticle *art = new KMime::NewsArticle();
    foreach ( uint field, entry.listFields() ) {
      if ( field >= KIO::UDSEntry::UDS_EXTRA && field <= KIO::UDSEntry::UDS_EXTRA_END ) {
        const QString value = entry.stringValue( field );
        int pos = value.indexOf( ':' );
        if ( pos >= value.length() - 1 )
          continue; // value is empty
        const QString hdrName = value.left( pos );
        const QString hdrValue = value.right( value.length() - ( hdrName.length() + 2 ) );

        if ( hdrName == "Subject" ) {
          art->subject()->from7BitString( hdrValue.toLatin1() );
          if ( art->subject()->isEmpty() )
            art->subject()->fromUnicodeString( i18n("no subject"), art->defaultCharset() );
        } else if ( hdrName == "From" ) {
          art->from()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Date" ) {
          art->date()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Message-ID" ) {
          art->messageID()->from7BitString( hdrValue.simplified().toLatin1() );
        } else if ( hdrName == "References" ) {
          if( !hdrValue.isEmpty() )
            art->references()->from7BitString( hdrValue.toLatin1() );
        } else if ( hdrName == "Lines" ) {
          art->lines()->setNumberOfLines( hdrValue.toInt() );
        } else {
          // optional extra headers
          art->setHeader( new KMime::Headers::Generic( hdrName.toLatin1(), art, hdrValue.toLatin1() ) );
        }
      }
    }

    item.setPayload( MessagePtr( art ) );
    ItemAppendJob *append = new ItemAppendJob( item, currentCollection(), session() );
    // TODO: check error
  }
}

void NntpResource::listGroupResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
  } else {
    // store last serial number
    Collection col = currentCollection();
    NntpCollectionAttribute *attr = col.attribute<NntpCollectionAttribute>( true );
    KIO::Job *j = static_cast<KIO::Job*>( job );
    if ( j->metaData().contains( "LastSerialNumber" ) )
      attr->setLastArticle( j->metaData().value("LastSerialNumber").toInt() );
    CollectionModifyJob *modify = new CollectionModifyJob( col, session() );
    modify->setAttribute( attr );
    // TODO: check result signal
  }

  itemsRetrieved();
}

KUrl NntpResource::baseUrl() const
{
  KUrl url;
 if ( Settings::self()->encryption() == Settings::SSL )
    url.setProtocol( "nntps" );
  else
    url.setProtocol( "nntp" );
  url.setHost( Settings::self()->server() );
  url.setPort( Settings::self()->port() );
  if ( Settings::self()->requiresAuthentication() ) {
    url.setUser( Settings::self()->userName() );
    url.setPass( Settings::self()->password() );
  }
  return url;
}

void NntpResource::fetchArticleResult(KJob * job)
{
  if ( job->error() ) {
    error( job->errorString() );
    return;
  }
  KIO::StoredTransferJob *j = static_cast<KIO::StoredTransferJob*>( job );
  KMime::Message *msg = new KMime::Message();
  msg->setContent( KMime::CRLFtoLF( j->data() ) );
  msg->parse();
  Item item = currentItem();
  item.setMimeType( "message/news" );
  item.setPayload( MessagePtr( msg ) );
  itemRetrieved( item );
}

void NntpResource::configure()
{
  ConfigDialog dlg;
  dlg.exec();
  if ( !Settings::self()->name().isEmpty() )
    setName( Settings::self()->name() );
}

void NntpResource::setupKioJob(KIO::Job * job) const
{
  Q_ASSERT( job );
  if ( Settings::self()->encryption() == Settings::TLS )
    job->addMetaData( "tls", "on" );
  else
    job->addMetaData( "tls", "off" );
  // TODO connect percent and status message signals to something
}

QString NntpResource::findParent(const QStringList & _path)
{
  QStringList path = _path;
  path.removeLast();
  if ( path.isEmpty() )
    return baseUrl().url();
  QString rid = path.join( "." );
  foreach ( const Collection col, remoteCollections )
    if ( col.remoteId() == rid )
      return col.remoteId();
  Collection parent;
  parent.setRemoteId( rid );
  QStringList ct;
  ct << Collection::collectionMimeType();
  parent.setContentTypes( ct );
  parent.setParentRemoteId( findParent( path ) );
  parent.setName( path.last() );
  remoteCollections << parent;
  return parent.remoteId();
}

void NntpResource::collectionChanged(const Akonadi::Collection & collection)
{
  if ( collection.remoteId() == baseUrl().url() && !collection.name().isEmpty() ) {
    Settings::self()->setName( collection.name() );
    setName( collection.name() );
  }
}

#include "nntpresource.moc"
<|endoftext|>


<commit_before>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "LiveFunctionsController.h"

#include <utility>

#include "App.h"
#include "OrbitClientData/FunctionUtils.h"
#include "TimeGraph.h"

using orbit_client_protos::FunctionInfo;
using orbit_client_protos::TimerInfo;

namespace {

std::pair<uint64_t, uint64_t> ComputeMinMaxTime(
    const absl::flat_hash_map<uint64_t, const TextBox*>& text_boxes) {
  uint64_t min_time = std::numeric_limits<uint64_t>::max();
  uint64_t max_time = std::numeric_limits<uint64_t>::min();
  for (auto& text_box : text_boxes) {
    min_time = std::min(min_time, text_box.second->GetTimerInfo().start());
    max_time = std::max(max_time, text_box.second->GetTimerInfo().start());
  }
  return std::make_pair(min_time, max_time);
}

uint64_t AbsDiff(uint64_t a, uint64_t b) {
  if (a > b) {
    return a - b;
  } else {
    return b - a;
  }
}

const TextBox* ClosestTo(uint64_t point, const TextBox* box_a, const TextBox* box_b) {
  uint64_t a_diff = AbsDiff(point, box_a->GetTimerInfo().start());
  uint64_t b_diff = AbsDiff(point, box_b->GetTimerInfo().start());
  if (a_diff <= b_diff) {
    return box_a;
  }
  return box_b;
}

const TextBox* SnapToClosestStart(uint64_t absolute_function_address) {
  double min_us = GCurrentTimeGraph->GetMinTimeUs();
  double max_us = GCurrentTimeGraph->GetMaxTimeUs();
  double center_us = 0.5 * max_us + 0.5 * min_us;
  uint64_t center = GCurrentTimeGraph->GetTickFromUs(center_us);

  // First, we find the next function call (text box) that has its end timestamp
  // after center - 1 (we use center - 1 to make sure that center itself is
  // included in the timerange that we search). Note that FindNextFunctionCall
  // uses the end marker of the timer as a timestamp.
  const TextBox* box =
      GCurrentTimeGraph->FindNextFunctionCall(absolute_function_address, center - 1);

  // If we cannot find a next function call, then the closest one is the first
  // call we find before center.
  if (!box) {
    return GCurrentTimeGraph->FindPreviousFunctionCall(absolute_function_address, center);
  }

  // We have to consider the case where center falls to the right of the start
  // marker of 'box'. In this case, the closest box can be any of two boxes:
  // 'box' or the next one. It cannot be any box before 'box' because we are
  // using the start marker to measure the distance.
  if (box->GetTimerInfo().start() <= center) {
    const TextBox* next_box = GCurrentTimeGraph->FindNextFunctionCall(absolute_function_address,
                                                                      box->GetTimerInfo().end());
    return ClosestTo(center, box, next_box);
  }

  // The center is to the left of 'box', so the closest box is either 'box' or
  // the next box to the left of the center.
  const TextBox* previous_box = GCurrentTimeGraph->FindPreviousFunctionCall(
      absolute_function_address, box->GetTimerInfo().start());

  if (!previous_box) {
    return box;
  }

  return ClosestTo(center, previous_box, box);
}

}  // namespace

void LiveFunctionsController::Move() {
  if (!current_textboxes_.empty()) {
    auto min_max = ComputeMinMaxTime(current_textboxes_);
    GCurrentTimeGraph->HorizontallyMoveIntoView(TimeGraph::VisibilityType::kFullyVisible,
                                                min_max.first, min_max.second, 0.5);
  }
  GCurrentTimeGraph->SetIteratorOverlayData(current_textboxes_, function_iterators_);
}

bool LiveFunctionsController::OnAllNextButton() {
  absl::flat_hash_map<uint64_t, const TextBox*> next_boxes;
  uint64_t id_with_min_timestamp = 0;
  uint64_t min_timestamp = std::numeric_limits<uint64_t>::max();
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  for (auto it : function_iterators_) {
    const FunctionInfo* function = it.second;
    auto function_address = capture_data.GetAbsoluteAddress(*function);
    const TextBox* current_box = current_textboxes_.find(it.first)->second;
    const TextBox* box = GCurrentTimeGraph->FindNextFunctionCall(function_address,
                                                                 current_box->GetTimerInfo().end());
    if (box == nullptr) {
      return false;
    }
    if (box->GetTimerInfo().start() < min_timestamp) {
      min_timestamp = box->GetTimerInfo().start();
      id_with_min_timestamp = it.first;
    }
    next_boxes.insert(std::make_pair(it.first, box));
  }

  // We only want to commit to the new boxes when all boxes can be moved.
  current_textboxes_ = next_boxes;
  id_to_select_ = id_with_min_timestamp;
  Move();
  return true;
}

bool LiveFunctionsController::OnAllPreviousButton() {
  absl::flat_hash_map<uint64_t, const TextBox*> next_boxes;
  uint64_t id_with_min_timestamp = 0;
  uint64_t min_timestamp = std::numeric_limits<uint64_t>::max();
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  for (auto it : function_iterators_) {
    const FunctionInfo* function = it.second;
    auto function_address = capture_data.GetAbsoluteAddress(*function);
    const TextBox* current_box = current_textboxes_.find(it.first)->second;
    const TextBox* box = GCurrentTimeGraph->FindPreviousFunctionCall(
        function_address, current_box->GetTimerInfo().end());
    if (box == nullptr) {
      return false;
    }
    if (box->GetTimerInfo().start() < min_timestamp) {
      min_timestamp = box->GetTimerInfo().start();
      id_with_min_timestamp = it.first;
    }
    next_boxes.insert(std::make_pair(it.first, box));
  }

  // We only want to commit to the new boxes when all boxes can be moved.
  current_textboxes_ = next_boxes;
  id_to_select_ = id_with_min_timestamp;
  Move();
  return true;
}

void LiveFunctionsController::OnNextButton(uint64_t id) {
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*(function_iterators_[id]));
  const TextBox* text_box = GCurrentTimeGraph->FindNextFunctionCall(
      function_address, current_textboxes_[id]->GetTimerInfo().end());
  // If text_box is nullptr, then we have reached the right end of the timeline.
  if (text_box != nullptr) {
    current_textboxes_[id] = text_box;
  }
  id_to_select_ = id;
  Move();
}
void LiveFunctionsController::OnPreviousButton(uint64_t id) {
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*(function_iterators_[id]));
  const TextBox* text_box = GCurrentTimeGraph->FindPreviousFunctionCall(
      function_address, current_textboxes_[id]->GetTimerInfo().end());
  // If text_box is nullptr, then we have reached the left end of the timeline.
  if (text_box != nullptr) {
    current_textboxes_[id] = text_box;
  }
  id_to_select_ = id;
  Move();
}

void LiveFunctionsController::OnDeleteButton(uint64_t id) {
  current_textboxes_.erase(id);
  function_iterators_.erase(id);
  // If we erase the iterator that was last used by the user, then
  // we need to switch last_id_pressed_ to an existing id.
  if (id == id_to_select_ && !current_textboxes_.empty()) {
    id_to_select_ = current_textboxes_.begin()->first;
  } else if (current_textboxes_.empty()) {
    // TODO: Not sure this is a good idea...
    id_to_select_ = 0;
  }
  Move();
}

void LiveFunctionsController::AddIterator(FunctionInfo* function) {
  uint64_t id = next_iterator_id_;
  ++next_iterator_id_;

  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*function);
  const TextBox* box = GOrbitApp->selected_text_box();
  // If no box is currently selected or the selected box is a different
  // function, we search for the closest box to the current center of the
  // screen.
  if (!box || box->GetTimerInfo().function_address() != function_address) {
    box = SnapToClosestStart(function_address);
  }

  function_iterators_.insert(std::make_pair(id, function));
  current_textboxes_.insert(std::make_pair(id, box));
  id_to_select_ = id;
  if (add_iterator_callback_) {
    add_iterator_callback_(id, function);
  }
  Move();
}

uint64_t LiveFunctionsController::GetStartTime(uint64_t index) {
  const auto& it = current_textboxes_.find(index);
  if (it != current_textboxes_.end()) {
    return it->second->GetTimerInfo().start();
  }
  return GetCaptureMin();
}

uint64_t LiveFunctionsController::GetCaptureMin() { return GCurrentTimeGraph->GetCaptureMin(); }
uint64_t LiveFunctionsController::GetCaptureMax() { return GCurrentTimeGraph->GetCaptureMax(); }

void LiveFunctionsController::Reset() {
  function_iterators_.clear();
  current_textboxes_.clear();
  GCurrentTimeGraph->SetIteratorOverlayData({}, {});
  next_iterator_id_ = 0;
  id_to_select_ = 0;
}
<commit_msg>Fix crash in iterators<commit_after>// Copyright (c) 2020 The Orbit Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "LiveFunctionsController.h"

#include <utility>

#include "App.h"
#include "OrbitClientData/FunctionUtils.h"
#include "TimeGraph.h"

using orbit_client_protos::FunctionInfo;
using orbit_client_protos::TimerInfo;

namespace {

std::pair<uint64_t, uint64_t> ComputeMinMaxTime(
    const absl::flat_hash_map<uint64_t, const TextBox*>& text_boxes) {
  uint64_t min_time = std::numeric_limits<uint64_t>::max();
  uint64_t max_time = std::numeric_limits<uint64_t>::min();
  for (auto& text_box : text_boxes) {
    min_time = std::min(min_time, text_box.second->GetTimerInfo().start());
    max_time = std::max(max_time, text_box.second->GetTimerInfo().start());
  }
  return std::make_pair(min_time, max_time);
}

uint64_t AbsDiff(uint64_t a, uint64_t b) {
  if (a > b) {
    return a - b;
  } else {
    return b - a;
  }
}

const TextBox* ClosestTo(uint64_t point, const TextBox* box_a, const TextBox* box_b) {
  uint64_t a_diff = AbsDiff(point, box_a->GetTimerInfo().start());
  uint64_t b_diff = AbsDiff(point, box_b->GetTimerInfo().start());
  if (a_diff <= b_diff) {
    return box_a;
  }
  return box_b;
}

const TextBox* SnapToClosestStart(uint64_t absolute_function_address) {
  double min_us = GCurrentTimeGraph->GetMinTimeUs();
  double max_us = GCurrentTimeGraph->GetMaxTimeUs();
  double center_us = 0.5 * max_us + 0.5 * min_us;
  uint64_t center = GCurrentTimeGraph->GetTickFromUs(center_us);

  // First, we find the next function call (text box) that has its end timestamp
  // after center - 1 (we use center - 1 to make sure that center itself is
  // included in the timerange that we search). Note that FindNextFunctionCall
  // uses the end marker of the timer as a timestamp.
  const TextBox* box =
      GCurrentTimeGraph->FindNextFunctionCall(absolute_function_address, center - 1);

  // If we cannot find a next function call, then the closest one is the first
  // call we find before center.
  if (!box) {
    return GCurrentTimeGraph->FindPreviousFunctionCall(absolute_function_address, center);
  }

  // We have to consider the case where center falls to the right of the start
  // marker of 'box'. In this case, the closest box can be any of two boxes:
  // 'box' or the next one. It cannot be any box before 'box' because we are
  // using the start marker to measure the distance.
  if (box->GetTimerInfo().start() <= center) {
    const TextBox* next_box = GCurrentTimeGraph->FindNextFunctionCall(absolute_function_address,
                                                                      box->GetTimerInfo().end());
    if (!next_box) {
      return box;
    }

    return ClosestTo(center, box, next_box);
  }

  // The center is to the left of 'box', so the closest box is either 'box' or
  // the next box to the left of the center.
  const TextBox* previous_box = GCurrentTimeGraph->FindPreviousFunctionCall(
      absolute_function_address, box->GetTimerInfo().start());

  if (!previous_box) {
    return box;
  }

  return ClosestTo(center, previous_box, box);
}

}  // namespace

void LiveFunctionsController::Move() {
  if (!current_textboxes_.empty()) {
    auto min_max = ComputeMinMaxTime(current_textboxes_);
    GCurrentTimeGraph->HorizontallyMoveIntoView(TimeGraph::VisibilityType::kFullyVisible,
                                                min_max.first, min_max.second, 0.5);
  }
  GCurrentTimeGraph->SetIteratorOverlayData(current_textboxes_, function_iterators_);
}

bool LiveFunctionsController::OnAllNextButton() {
  absl::flat_hash_map<uint64_t, const TextBox*> next_boxes;
  uint64_t id_with_min_timestamp = 0;
  uint64_t min_timestamp = std::numeric_limits<uint64_t>::max();
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  for (auto it : function_iterators_) {
    const FunctionInfo* function = it.second;
    auto function_address = capture_data.GetAbsoluteAddress(*function);
    const TextBox* current_box = current_textboxes_.find(it.first)->second;
    const TextBox* box = GCurrentTimeGraph->FindNextFunctionCall(function_address,
                                                                 current_box->GetTimerInfo().end());
    if (box == nullptr) {
      return false;
    }
    if (box->GetTimerInfo().start() < min_timestamp) {
      min_timestamp = box->GetTimerInfo().start();
      id_with_min_timestamp = it.first;
    }
    next_boxes.insert(std::make_pair(it.first, box));
  }

  // We only want to commit to the new boxes when all boxes can be moved.
  current_textboxes_ = next_boxes;
  id_to_select_ = id_with_min_timestamp;
  Move();
  return true;
}

bool LiveFunctionsController::OnAllPreviousButton() {
  absl::flat_hash_map<uint64_t, const TextBox*> next_boxes;
  uint64_t id_with_min_timestamp = 0;
  uint64_t min_timestamp = std::numeric_limits<uint64_t>::max();
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  for (auto it : function_iterators_) {
    const FunctionInfo* function = it.second;
    auto function_address = capture_data.GetAbsoluteAddress(*function);
    const TextBox* current_box = current_textboxes_.find(it.first)->second;
    const TextBox* box = GCurrentTimeGraph->FindPreviousFunctionCall(
        function_address, current_box->GetTimerInfo().end());
    if (box == nullptr) {
      return false;
    }
    if (box->GetTimerInfo().start() < min_timestamp) {
      min_timestamp = box->GetTimerInfo().start();
      id_with_min_timestamp = it.first;
    }
    next_boxes.insert(std::make_pair(it.first, box));
  }

  // We only want to commit to the new boxes when all boxes can be moved.
  current_textboxes_ = next_boxes;
  id_to_select_ = id_with_min_timestamp;
  Move();
  return true;
}

void LiveFunctionsController::OnNextButton(uint64_t id) {
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*(function_iterators_[id]));
  const TextBox* text_box = GCurrentTimeGraph->FindNextFunctionCall(
      function_address, current_textboxes_[id]->GetTimerInfo().end());
  // If text_box is nullptr, then we have reached the right end of the timeline.
  if (text_box != nullptr) {
    current_textboxes_[id] = text_box;
  }
  id_to_select_ = id;
  Move();
}
void LiveFunctionsController::OnPreviousButton(uint64_t id) {
  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*(function_iterators_[id]));
  const TextBox* text_box = GCurrentTimeGraph->FindPreviousFunctionCall(
      function_address, current_textboxes_[id]->GetTimerInfo().end());
  // If text_box is nullptr, then we have reached the left end of the timeline.
  if (text_box != nullptr) {
    current_textboxes_[id] = text_box;
  }
  id_to_select_ = id;
  Move();
}

void LiveFunctionsController::OnDeleteButton(uint64_t id) {
  current_textboxes_.erase(id);
  function_iterators_.erase(id);
  // If we erase the iterator that was last used by the user, then
  // we need to switch last_id_pressed_ to an existing id.
  if (id == id_to_select_ && !current_textboxes_.empty()) {
    id_to_select_ = current_textboxes_.begin()->first;
  } else if (current_textboxes_.empty()) {
    // TODO: Not sure this is a good idea...
    id_to_select_ = 0;
  }
  Move();
}

void LiveFunctionsController::AddIterator(FunctionInfo* function) {
  uint64_t id = next_iterator_id_;
  ++next_iterator_id_;

  const CaptureData& capture_data = GOrbitApp->GetCaptureData();
  auto function_address = capture_data.GetAbsoluteAddress(*function);
  const TextBox* box = GOrbitApp->selected_text_box();
  // If no box is currently selected or the selected box is a different
  // function, we search for the closest box to the current center of the
  // screen.
  if (!box || box->GetTimerInfo().function_address() != function_address) {
    box = SnapToClosestStart(function_address);
  }

  function_iterators_.insert(std::make_pair(id, function));
  current_textboxes_.insert(std::make_pair(id, box));
  id_to_select_ = id;
  if (add_iterator_callback_) {
    add_iterator_callback_(id, function);
  }
  Move();
}

uint64_t LiveFunctionsController::GetStartTime(uint64_t index) {
  const auto& it = current_textboxes_.find(index);
  if (it != current_textboxes_.end()) {
    return it->second->GetTimerInfo().start();
  }
  return GetCaptureMin();
}

uint64_t LiveFunctionsController::GetCaptureMin() { return GCurrentTimeGraph->GetCaptureMin(); }
uint64_t LiveFunctionsController::GetCaptureMax() { return GCurrentTimeGraph->GetCaptureMax(); }

void LiveFunctionsController::Reset() {
  function_iterators_.clear();
  current_textboxes_.clear();
  GCurrentTimeGraph->SetIteratorOverlayData({}, {});
  next_iterator_id_ = 0;
  id_to_select_ = 0;
}
<|endoftext|>