Select Git revision
MTriangle.h
-
Amaury Johnen authoredAmaury Johnen authored
onelab.h 42.72 KiB
// OneLab - Copyright (C) 2011-2012 ULg-UCL
//
// 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, and/or sell copies of the
// Software, and to permit persons to whom the Software is furnished
// to do so, provided that the above copyright notice(s) and this
// permission notice appear in all copies of the Software and that
// both the above copyright notice(s) and this permission notice
// appear in supporting documentation.
//
// 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 OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE
// COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR
// ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY
// DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
// WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
// ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
// OF THIS SOFTWARE.
//
// Please report all bugs and problems to <gmsh@geuz.org>.
#ifndef _ONELAB_H_
#define _ONELAB_H_
#include <time.h>
#include <stdio.h>
#include <string>
#include <vector>
#include <set>
#include <map>
#include <iostream>
#include <sstream>
#include "GmshSocket.h"
namespace onelab{
// The base parameter class.
class parameter{
private:
// the name of the parameter, including its '/'-separated path in the
// parameter hierarchy. Parameters or subpaths can start with numbers to
// force their relative ordering (such numbers are automatically hidden in
// the interface).
std::string _name;
// the parameter label: if provided it serves as a better way to display the
// parameter in the interface (richer encoding (UTF? HTML?) might be used in
// the future)
std::string _label;
// a help string (richer encoding (UTF? HTML?) might be used in the future)
std::string _help;
// clients that use this parameter
std::set<std::string> _clients;
// flag to check if the value of the parameter has been changed since the
// last computation (normally this is reset after all the clients have been
// run)
bool _changed;
// flag indicating that the _changed flag of this parameter will always be
// reset to false when the parameter is updated
bool _neverChanged;
// should the parameter be visible in the interface?
bool _visible;
// sould the paramete be "read-only" (not settable by the user)
bool _readOnly;
protected:
// optional additional attributes
std::map<std::string, std::string> _attributes;
public:
parameter(const std::string &name="", const std::string &label="",
const std::string &help="")
: _name(name), _label(label), _help(help), _changed(true),
_neverChanged(false), _visible(true), _readOnly(false) {}
virtual ~parameter(){}
void setName(const std::string &name){ _name = name; }
void setLabel(const std::string &label){ _label = label; }
void setHelp(const std::string &help){ _help = help; }
void setChanged(bool changed){ _changed = changed; }
void setNeverChanged(bool never){ _neverChanged = never; }
void setVisible(bool visible){ _visible = visible; }
void setReadOnly(bool readOnly){ _readOnly = readOnly; }
void setAttribute(const std::string &key, const std::string &value)
{
_attributes[key] = value;
}
void setAttributes(const std::map<std::string, std::string> &attributes)
{
_attributes = attributes;
}
void setClients(const std::set<std::string> &clients){ _clients = clients; }
void addClient(const std::string &client){ _clients.insert(client); }
void addClients(const std::set<std::string> &clients)
{
_clients.insert(clients.begin(), clients.end());
}
bool hasClient(const std::string &client)
{
return (_clients.find(client) != _clients.end());
}
virtual std::string getType() const = 0;
const std::string &getName() const { return _name; }
const std::string &getLabel() const { return _label; }
const std::string &getHelp() const { return _help; }
std::string getPath() const
{
std::string::size_type last = _name.find_last_of('/');
return _name.substr(0, last);
}
std::string getShortName() const
{
if(_label.size()) return _label;
std::string s = _name;
// remove path
std::string::size_type last = _name.find_last_of('/');
if(last != std::string::npos)
s = _name.substr(last + 1);
// remove starting numbers
while(s.size() && s[0] >= '0' && s[0] <= '9')
s = s.substr(1);
return s;
}
bool getChanged() const { return _changed; }
bool getNeverChanged() const { return _neverChanged; }
bool getVisible() const { return _visible; }
bool getReadOnly() const { return _readOnly; }
std::string getAttribute(const std::string &key) const
{
std::map<std::string, std::string>::const_iterator it = _attributes.find(key);
if(it != _attributes.end()) return it->second;
return "";
}
const std::map<std::string, std::string> &getAttributes() const
{
return _attributes;
}
const std::set<std::string> &getClients() const { return _clients; }
static char charSep() { return '\0'; }
static double maxNumber() { return 1e200; }
static std::string version() { return "1.05"; }
static std::string getNextToken(const std::string &msg,
std::string::size_type &first,
char separator=charSep())
{
if(first == std::string::npos) return "";
std::string::size_type last = msg.find_first_of(separator, first);
std::string next = msg.substr(first, last - first);
first = (last == std::string::npos) ? last : last + 1;
return next;
}
static std::vector<std::string> split(const std::string &msg,
char separator=charSep())
{
std::vector<std::string> out;
std::string::size_type first = 0;
while(first != std::string::npos)
out.push_back(getNextToken(msg, first, separator));
return out;
}
std::string sanitize(const std::string &in) const
{
std::string out(in);
for(unsigned int i = 0; i < in.size(); i++)
if(out[i] == charSep()) out[i] = ' ';
return out;
}
virtual std::string toChar() const
{
std::ostringstream sstream;
sstream << version() << charSep() << getType() << charSep()
<< sanitize(getName()) << charSep()
<< sanitize(getLabel()) << charSep()
<< sanitize(getHelp()) << charSep()
<< (getNeverChanged() ? 1 : 0) << charSep()
<< (getChanged() ? 1 : 0) << charSep()
<< (getVisible() ? 1 : 0) << charSep()
<< (getReadOnly() ? 1 : 0) << charSep()
<< _attributes.size() << charSep();
for(std::map<std::string, std::string>::const_iterator it = _attributes.begin();
it != _attributes.end(); it++)
sstream << sanitize(it->first) << charSep()
<< sanitize(it->second) << charSep();
sstream << getClients().size() << charSep();
for(std::set<std::string>::const_iterator it = getClients().begin();
it != getClients().end(); it++)
sstream << sanitize(*it) << charSep();
return sstream.str();
}
virtual std::string::size_type fromChar(const std::string &msg)
{
std::string::size_type pos = 0;
if(getNextToken(msg, pos) != version()) return 0;
if(getNextToken(msg, pos) != getType()) return 0;
setName(getNextToken(msg, pos));
setLabel(getNextToken(msg, pos));
setHelp(getNextToken(msg, pos));
setNeverChanged(atoi(getNextToken(msg, pos).c_str()));
setChanged(atoi(getNextToken(msg, pos).c_str()));
setVisible(atoi(getNextToken(msg, pos).c_str()));
setReadOnly(atoi(getNextToken(msg, pos).c_str()));
int numAttributes = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < numAttributes; i++){
std::string key(getNextToken(msg, pos));
setAttribute(key, getNextToken(msg, pos));
}
int numClients = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < numClients; i++){
std::string client(getNextToken(msg, pos));
addClient(client);
}
return pos;
}
static void getInfoFromChar(const std::string &msg, std::string &version,
std::string &type, std::string &name)
{
std::string::size_type first = 0;
version = getNextToken(msg, first);
type = getNextToken(msg, first);
name = getNextToken(msg, first);
}
static bool fromFile(std::vector<std::string> &msg,
const std::string &fileName)
{
msg.clear();
FILE *fp = fopen(fileName.c_str(), "rb");
if(!fp) return false;
char tmp[1000];
if(!fgets(tmp, sizeof(tmp), fp)) return false; // first line is comment
while(!feof(fp)){
int numc = 0;
if(!fscanf(fp, "%d ", &numc)) break; // space is important
if(!numc) break;
msg.push_back("");
for(int i = 0; i < numc; i++)
msg.back() += fgetc(fp);
if(!fgets(tmp, sizeof(tmp), fp)) break; // end of line
}
fclose(fp);
return true;
}
static bool toFile(const std::vector<std::string> &msg,
const std::string &fileName,
const std::string &creator)
{
FILE *fp = fopen(fileName.c_str(), "wb");
if(!fp) return false;
time_t now;
time(&now);
fprintf(fp, "OneLab database created by %s on %s",
creator.c_str(), ctime(&now));
for(unsigned int i = 0; i < msg.size(); i++){
fprintf(fp, "%d ", (int)msg[i].size());
for(unsigned int j = 0; j < msg[i].size(); j++)
fputc(msg[i][j], fp);
fputc('\n', fp);
}
fclose(fp);
return true;
}
};
class parameterLessThan{
public:
bool operator()(const parameter *p1, const parameter *p2) const
{
return p1->getName() < p2->getName();
}
};
// The number class. Numbers are stored internally as double precision real
// numbers. All more complicated types (complex numbers, vectors, etc.) are
// supposed to be either exchanged as strings or encapsulated in functions.
class number : public parameter{
private:
double _value, _min, _max, _step;
// when in a loop, indicates current index in the vector _choices; is -1
// when not in a loop
int _index;
std::vector<double> _choices;
std::map<double, std::string> _valueLabels;
public:
number(const std::string &name="", double value=0.,
const std::string &label="", const std::string &help="")
: parameter(name, label, help), _value(value),
_min(-maxNumber()), _max(maxNumber()), _step(0.), _index(0) {}
void setValue(double value){ _value = value; }
void setMin(double min){ _min = min; }
void setMax(double max){ _max = max; }
void setStep(double step){ _step = step; }
void setIndex(int index){ _index = index; }
void setChoices(const std::vector<double> &choices){ _choices = choices; }
void setChoiceLabels(const std::vector<std::string> &labels)
{
if(labels.size() != _choices.size()) return;
for(unsigned int i = 0; i < _choices.size(); i++)
_valueLabels[_choices[i]] = labels[i];
}
void setValueLabels(const std::map<double, std::string> &valueLabels)
{
_valueLabels = valueLabels;
}
void setValueLabel(double value, const std::string &label)
{
_valueLabels[value] = label;
}
std::string getType() const { return "number"; }
double getValue() const { return _value; }
double getMin() const { return _min; }
double getMax() const { return _max; }
double getStep() const { return _step; }
int getIndex() const { return _index; }
const std::vector<double> &getChoices() const { return _choices; }
const std::map<double, std::string> &getValueLabels() const
{
return _valueLabels;
}
std::string getValueLabel(double value) const
{
std::map<double, std::string>::const_iterator it = _valueLabels.find(value);
if(it != _valueLabels.end()) return it->second;
return "";
}
void update(const number &p)
{
addClients(p.getClients()); // complete the list of clients
setLabel(p.getLabel());
setHelp(p.getHelp());
setVisible(p.getVisible());
setReadOnly(p.getReadOnly());
setAttributes(p.getAttributes());
if(p.getValue() != getValue()){
setValue(p.getValue());
setChanged(true);
}
setMin(p.getMin());
setMax(p.getMax());
setStep(p.getStep());
setIndex(p.getIndex());
setChoices(p.getChoices());
setValueLabels(p.getValueLabels());
if(getNeverChanged()) setChanged(false);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream << parameter::toChar() << _value << charSep()
<< _min << charSep() << _max << charSep() << _step << charSep()
<< _index << charSep()
<< _choices.size() << charSep();
for(unsigned int i = 0; i < _choices.size(); i++)
sstream << _choices[i] << charSep();
sstream << _valueLabels.size() << charSep();
for(std::map<double, std::string>::const_iterator it = _valueLabels.begin();
it != _valueLabels.end(); it++){
sstream << it->first << charSep();
sstream << sanitize(it->second) << charSep();
}
return sstream.str();
}
std::string::size_type fromChar(const std::string &msg)
{
std::string::size_type pos = parameter::fromChar(msg);
if(!pos) return 0;
setValue(atof(getNextToken(msg, pos).c_str()));
setMin(atof(getNextToken(msg, pos).c_str()));
setMax(atof(getNextToken(msg, pos).c_str()));
setStep(atof(getNextToken(msg, pos).c_str()));
setIndex(atoi(getNextToken(msg, pos).c_str()));
_choices.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _choices.size(); i++)
_choices[i] = atof(getNextToken(msg, pos).c_str());
int numValueLabels = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < numValueLabels; i++){
double value = atof(getNextToken(msg, pos).c_str());
_valueLabels[value] = getNextToken(msg, pos);
}
return pos;
}
};
// The string class. A string has a mutable "kind": we do not derive
// specialized classes, because the kind should be changeable at runtime
// (e.g. from a client-dependent mathematical expression to a table of
// values). Kinds currently recognized by Gmsh are: "file". Possible kinds
// could be "complex", "matrix m n", "hostname", client-dependent mathematical
// expression, onelab mathematical expression (through mathex?), ...
class string : public parameter{
private:
std::string _value, _kind;
std::vector<std::string> _choices;
public:
string(const std::string &name="", const std::string &value="",
const std::string &label="", const std::string &help="")
: parameter(name, label, help), _value(value), _kind("generic") {}
void setValue(const std::string &value){ _value = value; }
void setKind(const std::string &kind){ _kind = kind; }
void setChoices(const std::vector<std::string> &choices){ _choices = choices; }
std::string getType() const { return "string"; }
const std::string &getValue() const { return _value; }
const std::string &getKind() const { return _kind; }
const std::vector<std::string> &getChoices() const { return _choices; }
void update(const string &p)
{
addClients(p.getClients());
setLabel(p.getLabel());
setHelp(p.getHelp());
setVisible(p.getVisible());
setReadOnly(p.getReadOnly());
setAttributes(p.getAttributes());
if(p.getValue() != getValue()){
setValue(p.getValue());
setChanged(true);
}
if(p.getKind() != getKind()){
setKind(p.getKind());
setChanged(true);
}
setChoices(p.getChoices());
if(getNeverChanged()) setChanged(false);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream << parameter::toChar() << sanitize(_value) << charSep()
<< sanitize(_kind) << charSep()
<< _choices.size() << charSep();
for(unsigned int i = 0; i < _choices.size(); i++)
sstream << sanitize(_choices[i]) << charSep();
return sstream.str();
}
std::string::size_type fromChar(const std::string &msg)
{
std::string::size_type pos = parameter::fromChar(msg);
if(!pos) return 0;
setValue(getNextToken(msg, pos));
setKind(getNextToken(msg, pos));
_choices.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _choices.size(); i++)
_choices[i] = getNextToken(msg, pos);
return pos;
}
};
// The region class. A region can be any kind of geometrical entity,
// represented as identifiers of physical regions. Operations on regions will
// include union, intersection, etc.
class region : public parameter{
private:
std::set<std::string> _value;
// optional geometrical dimension
int _dimension;
std::vector<std::set<std::string> > _choices;
public:
region(const std::string &name="",
const std::set<std::string> &value = std::set<std::string>(),
const std::string &label="", const std::string &help="")
: parameter(name, label, help), _value(value), _dimension(-1) {}
region(const std::string &name, const std::string &value,
const std::string &label="", const std::string &help="")
: parameter(name, label, help), _dimension(-1)
{
if(value.size()) _value.insert(value);
}
void setValue(const std::set<std::string> &value){ _value = value; }
void setDimension(int dim){ _dimension = dim; }
void setChoices(const std::vector<std::set<std::string> > &choices)
{
_choices = choices;
}
std::string getType() const { return "region"; }
const std::set<std::string> &getValue() const { return _value; }
int getDimension() const { return _dimension; }
const std::vector<std::set<std::string> > &getChoices() const
{
return _choices;
}
void update(const region &p)
{
addClients(p.getClients());
setLabel(p.getLabel());
setHelp(p.getHelp());
setAttributes(p.getAttributes());
if(p.getValue() != getValue()){
setValue(p.getValue());
setChanged(true);
}
setDimension(p.getDimension());
setChoices(p.getChoices());
if(getNeverChanged()) setChanged(false);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream << parameter::toChar() << _value.size() << charSep();
for(std::set<std::string>::const_iterator it = _value.begin();
it != _value.end(); it++)
sstream << sanitize(*it) << charSep();
sstream << _dimension << charSep();
sstream << _choices.size() << charSep();
for(unsigned int i = 0; i < _choices.size(); i++){
sstream << _choices[i].size() << charSep();
for(std::set<std::string>::const_iterator it = _choices[i].begin();
it != _choices[i].end(); it++)
sstream << sanitize(*it) << charSep();
}
return sstream.str();
}
std::string::size_type fromChar(const std::string &msg)
{
std::string::size_type pos = parameter::fromChar(msg);
if(!pos) return 0;
int n = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < n; i++)
_value.insert(getNextToken(msg, pos));
setDimension(atoi(getNextToken(msg, pos).c_str()));
_choices.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _choices.size(); i++){
n = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < n; i++)
_choices[i].insert(getNextToken(msg, pos));
}
return pos;
}
};
// The (possibly piece-wise defined on regions) function class. Functions are
// entirely client-dependent: they are just represented internally as onelab
// strings, defined on onelab regions.
class function : public parameter{
private:
std::map<std::string, std::string> _value;
std::vector<std::map<std::string, std::string> > _choices;
public:
function(const std::string &name="") : parameter(name, "", "") {}
function(const std::string &name, const std::map<std::string, std::string> &value,
const std::string &label="", const std::string &help="")
: parameter(name, label, help), _value(value) {}
void setValue(const std::map<std::string, std::string> &value)
{
_value = value;
}
void setChoices(const std::vector<std::map<std::string, std::string> > &choices)
{
_choices = choices;
}
std::string getType() const { return "function"; }
const std::map<std::string, std::string> &getValue() const { return _value; }
const std::string getValue(const std::string ®ion) const
{
std::map<std::string, std::string>::const_iterator it = _value.find(region);
if(it != _value.end()) return it->second;
return "";
}
const std::vector<std::map<std::string, std::string> > &getChoices() const
{
return _choices;
}
void update(const function &p)
{
addClients(p.getClients());
setLabel(p.getLabel());
setHelp(p.getHelp());
setAttributes(p.getAttributes());
if(p.getValue() != getValue()){
setValue(p.getValue());
setChanged(true);
}
setChoices(p.getChoices());
if(getNeverChanged()) setChanged(false);
}
std::string toChar() const
{
std::ostringstream sstream;
sstream << parameter::toChar() << _value.size() << charSep();
for(std::map<std::string, std::string>::const_iterator it = _value.begin();
it != _value.end(); it++)
sstream << sanitize(it->first) << charSep()
<< sanitize(it->second) << charSep();
sstream << _choices.size() << charSep();
for(unsigned int i = 0; i < _choices.size(); i++){
sstream << _choices[i].size() << charSep();
for(std::map<std::string, std::string>::const_iterator it = _choices[i].begin();
it != _choices[i].end(); it++)
sstream << sanitize(it->first) << charSep()
<< sanitize(it->second) << charSep();
}
return sstream.str();
}
std::string::size_type fromChar(const std::string &msg)
{
std::string::size_type pos = parameter::fromChar(msg);
if(!pos) return 0;
int n = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < n; i++){
std::string key = getNextToken(msg, pos);
_value[key] = getNextToken(msg, pos);
}
_choices.resize(atoi(getNextToken(msg, pos).c_str()));
for(unsigned int i = 0; i < _choices.size(); i++){
n = atoi(getNextToken(msg, pos).c_str());
for(int i = 0; i < n; i++){
std::string key = getNextToken(msg, pos);
_choices[i][key] = getNextToken(msg, pos);
}
}
return pos;
}
};
// The parameter space, i.e., the set of parameters stored and handled by the
// onelab server.
class parameterSpace{
private:
std::set<number*, parameterLessThan> _numbers;
std::set<string*, parameterLessThan> _strings;
std::set<region*, parameterLessThan> _regions;
std::set<function*, parameterLessThan> _functions;
// set a parameter in the parameter space; if it already exists, update it
// (adding new clients if necessary). This needs to be locked to avoid race
// conditions when several clients try to set a parameter at the same time.
template <class T> bool _set(const T &p, const std::string &client,
std::set<T*, parameterLessThan> &ps)
{
typename std::set<T*, parameterLessThan>::iterator it = ps.find((T*)&p);
if(it != ps.end()){
(*it)->update(p);
if(client.size()) (*it)->addClient(client);
}
else{
T* newp = new T(p);
if(client.size()) newp->addClient(client);
ps.insert(newp);
}
return true;
}
// get the parameter matching the given name, or all the parameters in the
// category if no name is given. If we find a given parameter by name, we
// add the client requesting the parameter to the list of clients for this
// parameter. This also needs to be locked.
template <class T> bool _get(std::vector<T> &p, const std::string &name,
const std::string &client,
std::set<T*, parameterLessThan> &ps)
{
p.clear();
if(name.empty()){
for(typename std::set<T*, parameterLessThan>::iterator it = ps.begin();
it != ps.end(); it++)
p.push_back(**it);
}
else{
T tmp(name);
typename std::set<T*, parameterLessThan>::iterator it = ps.find(&tmp);
if(it != ps.end()){
if(client.size()) (*it)->addClient(client);
p.push_back(**it);
}
}
return true;
}
void _getAllParameters(std::set<parameter*> &ps) const
{
ps.insert(_numbers.begin(), _numbers.end());
ps.insert(_strings.begin(), _strings.end());
ps.insert(_regions.begin(), _regions.end());
ps.insert(_functions.begin(), _functions.end());
}
public:
parameterSpace(){}
~parameterSpace(){ clear(); }
void clear()
{
std::set<parameter*> ps;
_getAllParameters(ps);
for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
delete *it;
_numbers.clear();
_strings.clear();
_regions.clear();
_functions.clear();
}
bool set(const number &p,
const std::string &client=""){ return _set(p, client, _numbers); }
bool set(const string &p,
const std::string &client=""){ return _set(p, client, _strings); }
bool set(const region &p,
const std::string &client=""){ return _set(p, client, _regions); }
bool set(const function &p,
const std::string &client=""){ return _set(p, client, _functions); }
bool get(std::vector<number> &ps, const std::string &name="",
const std::string &client=""){ return _get(ps, name, client, _numbers); }
bool get(std::vector<string> &ps, const std::string &name="",
const std::string &client=""){ return _get(ps, name, client, _strings); }
bool get(std::vector<region> &ps, const std::string &name="",
const std::string &client=""){ return _get(ps, name, client, _regions); }
bool get(std::vector<function> &ps, const std::string &name="",
const std::string &client=""){ return _get(ps, name, client, _functions); }
unsigned int getNumParameters()
{
return _numbers.size() + _strings.size() + _regions.size() + _functions.size();
}
// check if at least one parameter depends on the given client
bool hasClient(const std::string &client) const
{
std::set<parameter*> ps;
_getAllParameters(ps);
for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
if((*it)->hasClient(client)) return true;
return false;
}
// check if some parameters have changed (optionnally only check the
// parameters that depend on a given client)
bool getChanged(const std::string &client="") const
{
std::set<parameter*> ps;
_getAllParameters(ps);
for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++){
if((client.empty() || (*it)->hasClient(client)) && (*it)->getChanged()){
return true;
}
}
return false;
}
// set the changed flag for all parameters (optionnally only affect those
// parameters that depend on a given client)
bool setChanged(bool changed, const std::string &client="")
{
std::set<parameter*> ps;
_getAllParameters(ps);
for(std::set<parameter*>::iterator it = ps.begin(); it != ps.end(); it++)
if(client.empty() || (*it)->hasClient(client))
(*it)->setChanged(changed);
return true;
}
// serialize the parameter space (optionally only serialize those parameters
// that depend on the given client)
std::vector<std::string> toChar(const std::string &client="") const
{
std::vector<std::string> s;
std::set<parameter*> ps;
_getAllParameters(ps);
for(std::set<parameter*>::const_iterator it = ps.begin(); it != ps.end(); it++)
if(client.empty() || (*it)->hasClient(client))
s.push_back((*it)->toChar());
return s;
}
// unserialize the parameter space
bool fromChar(const std::vector<std::string> &msg, const std::string &client="")
{
for(unsigned int i = 0; i < msg.size(); i++){
std::string version, type, name;
onelab::parameter::getInfoFromChar(msg[i], version, type, name);
if(onelab::parameter::version() != version) return false;
if(type == "number"){
onelab::number p; p.fromChar(msg[i]); set(p, client);
}
else if(type == "string"){
onelab::string p; p.fromChar(msg[i]); set(p, client);
}
else if(type == "region"){
onelab::region p; p.fromChar(msg[i]); set(p, client);
}
else if(type == "function"){
onelab::function p; p.fromChar(msg[i]); set(p, client);
}
else
return false;
}
return true;
}
};
// The onelab client: a class that communicates with the onelab server. Each
// client should be derived from this one. A client can be understood as "one
// simulation step in a complex computation".
class client{
protected:
// the name of the client
std::string _name;
// the id of the client, used to create a unique socket for this client
int _id;
// the index of the client in an external client list (if any)
int _index;
public:
client(const std::string &name) : _name(name), _id(0), _index(-1){}
virtual ~client(){}
std::string getName(){ return _name; }
void setId(int id){ _id = id; }
int getId(){ return _id; }
void setIndex(int index){ _index = index; }
int getIndex(){ return _index; }
virtual bool run(){ return false; }
virtual bool isNetworkClient(){ return false; }
virtual bool kill(){ return false; }
virtual void sendInfo(const std::string &msg){ std::cout << msg << std::endl; }
virtual void sendWarning(const std::string &msg){ std::cerr << msg << std::endl; }
virtual void sendError(const std::string &msg){ std::cerr << msg << std::endl; }
virtual void sendProgress(const std::string &msg){ std::cout << msg << std::endl; }
virtual void sendMergeFileRequest(const std::string &msg){}
virtual void sendParseStringRequest(const std::string &msg){}
virtual void sendVertexArray(const std::string &msg){}
virtual bool set(const number &p) = 0;
virtual bool set(const string &p) = 0;
virtual bool set(const region &p) = 0;
virtual bool set(const function &p) = 0;
virtual bool get(std::vector<number> &ps, const std::string &name="") = 0;
virtual bool get(std::vector<string> &ps, const std::string &name="") = 0;
virtual bool get(std::vector<region> &ps, const std::string &name="") = 0;
virtual bool get(std::vector<function> &ps, const std::string &name="") = 0;
std::vector<std::string> toChar()
{
std::vector<std::string> out;
std::vector<number> n; get(n);
for(unsigned int i = 0; i < n.size(); i++) out.push_back(n[i].toChar());
std::vector<number> s; get(s);
for(unsigned int i = 0; i < s.size(); i++) out.push_back(s[i].toChar());
std::vector<region> r; get(r);
for(unsigned int i = 0; i < r.size(); i++) out.push_back(r[i].toChar());
std::vector<region> f; get(f);
for(unsigned int i = 0; i < f.size(); i++) out.push_back(f[i].toChar());
return out;
}
bool fromChar(const std::vector<std::string> &msg)
{
for(unsigned int i = 0; i < msg.size(); i++){
std::string version, type, name;
onelab::parameter::getInfoFromChar(msg[i], version, type, name);
if(onelab::parameter::version() != version) return false;
if(type == "number"){
onelab::number p; p.fromChar(msg[i]); set(p);
}
else if(type == "string"){
onelab::string p; p.fromChar(msg[i]); set(p);
}
else if(type == "region"){
onelab::region p; p.fromChar(msg[i]); set(p);
}
else if(type == "function"){
onelab::function p; p.fromChar(msg[i]); set(p);
}
else
return false;
}
return true;
}
bool toFile(const std::string &fileName)
{
return parameter::toFile(toChar(), fileName, getName());
}
bool fromFile(const std::string &fileName)
{
std::vector<std::string> msg;
if(parameter::fromFile(msg, fileName)) return fromChar(msg);
return false;
}
};
// The onelab server: a singleton that stores the parameter space and
// interacts with onelab clients.
class server{
private:
// the unique server (singleton behaviour due to the "static" specifier)
static server *_server;
// the address of the server
std::string _address;
// the connected clients, indexed by name
std::map<std::string, client*> _clients;
// the parameter space
parameterSpace _parameterSpace;
public:
server(const std::string &address="") : _address(address) {}
~server(){}
static server *instance(const std::string &address="")
{
if(!_server) _server = new server(address);
return _server;
}
void clear(){ _parameterSpace.clear(); }
template <class T> bool set(const T &p, const std::string &client="")
{
return _parameterSpace.set(p, client);
}
template <class T> bool get(std::vector<T> &ps, const std::string &name="",
const std::string &client="")
{
return _parameterSpace.get(ps, name, client);
}
typedef std::map<std::string, client*>::iterator citer;
citer firstClient(){ return _clients.begin(); }
citer lastClient(){ return _clients.end(); }
int getNumClients() { return _clients.size(); };
citer findClient(const std::string &name){ return _clients.find(name); }
void registerClient(client *c)
{
_clients[c->getName()] = c;
c->setId(_clients.size());
}
void unregisterClient(client *c){ _clients.erase(c->getName()); }
void setChanged(bool changed, const std::string &client="")
{
_parameterSpace.setChanged(changed, client);
}
bool getChanged(const std::string &client="")
{
return _parameterSpace.getChanged(client);
}
unsigned int getNumParameters(){ return _parameterSpace.getNumParameters(); }
std::vector<std::string> toChar(const std::string &client="")
{
return _parameterSpace.toChar(client);
}
bool fromChar(const std::vector<std::string> &msg, const std::string &client="")
{
return _parameterSpace.fromChar(msg, client);
}
bool toFile(const std::string &fileName, const std::string &client="")
{
return parameter::toFile(toChar(client), fileName, "onelab server");
}
bool fromFile(const std::string &fileName, const std::string &client="")
{
std::vector<std::string> msg;
if(parameter::fromFile(msg, fileName)) return fromChar(msg, client);
return false;
}
};
class localClient : public client{
private:
template <class T> bool _set(const T &p)
{
server::instance()->set(p, _name);
return true;
}
template <class T> bool _get(std::vector<T> &ps,
const std::string &name="")
{
server::instance()->get(ps, name, _name);
return true;
}
public:
localClient(const std::string &name) : client(name)
{
server::instance()->registerClient(this);
}
virtual ~localClient(){}
virtual bool set(const number &p){ return _set(p); }
virtual bool set(const string &p){ return _set(p); }
virtual bool set(const function &p){ return _set(p); }
virtual bool set(const region &p){ return _set(p); }
virtual bool get(std::vector<number> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<string> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<function> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<region> &ps,
const std::string &name=""){ return _get(ps, name); }
};
class localNetworkClient : public localClient{
private:
// executable of the client (including filesystem path, if necessary)
std::string _executable;
// command to login to a remote host (if necessary)
std::string _remoteLogin;
// command line option to specify socket
std::string _socketSwitch;
// pid of the remote network client while it is running (-1 otherwise)
int _pid;
// underlying GmshServer
GmshServer *_gmshServer;
public:
localNetworkClient(const std::string &name, const std::string &executable,
const std::string &remoteLogin="")
: localClient(name), _executable(executable), _remoteLogin(remoteLogin),
_socketSwitch("-onelab"), _pid(-1), _gmshServer(0) {}
virtual ~localNetworkClient(){}
virtual bool isNetworkClient(){ return true; }
const std::string &getExecutable(){ return _executable; }
void setExecutable(const std::string &s){ _executable = s; }
const std::string &getRemoteLogin(){ return _remoteLogin; }
void setRemoteLogin(const std::string &s){ _remoteLogin = s; }
const std::string &getSocketSwitch(){ return _socketSwitch; }
void setSocketSwitch(const std::string &s){ _socketSwitch = s; }
int getPid(){ return _pid; }
void setPid(int pid){ _pid = pid; }
GmshServer *getGmshServer(){ return _gmshServer; }
void setGmshServer(GmshServer *server){ _gmshServer = server; }
virtual bool run();
virtual bool kill();
};
class remoteNetworkClient : public client{
private:
// address (inet:port or unix socket) of the server
std::string _serverAddress;
// underlying GmshClient
GmshClient *_gmshClient;
template <class T> bool _set(const T &p)
{
if(!_gmshClient) return false;
std::string msg = p.toChar();
_gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER, msg.size(), &msg[0]);
return true;
}
template <class T> bool _get(std::vector<T> &ps,
const std::string &name="")
{
ps.clear();
if(!_gmshClient) return false;
T p(name);
std::string msg = p.toChar();
if (name.size())
_gmshClient->SendMessage(GmshSocket::GMSH_PARAMETER_QUERY, msg.size(), &msg[0]);
else //get all parameters
_gmshClient->SendMessage(GmshSocket::GMSH_PARAM_QUERY_ALL, msg.size(), &msg[0]);
while(1){
// stop if we have no communications for 5 minutes
int ret = _gmshClient->Select(500, 0);
if(!ret){
_gmshClient->Info("Timout: aborting remote get");
return false;
}
else if(ret < 0){
_gmshClient->Error("Error on select: aborting remote get");
return false;
}
int type, length, swap;
if(!_gmshClient->ReceiveHeader(&type, &length, &swap)){
_gmshClient->Error("Did not receive message header: aborting remote get");
return false;
}
std::string msg(length, ' ');
if(!_gmshClient->ReceiveMessage(length, &msg[0])){
_gmshClient->Error("Did not receive message body: aborting remote get");
return false;
}
if(type == GmshSocket::GMSH_PARAMETER){
T p;
p.fromChar(msg);
ps.push_back(p);
return true;
}
if(type == GmshSocket::GMSH_PARAM_QUERY_ALL){
T p;
p.fromChar(msg);
ps.push_back(p);
// do NOT return until all parameters have been downloaded
}
else if(type == GmshSocket::GMSH_PARAM_QUERY_END){
return true;
}
else if(type == GmshSocket::GMSH_INFO){
// parameter not found or all aparameters have been sent
return true;
}
else{
_gmshClient->Error("Unknown message type: aborting remote get");
return false;
}
}
return true;
}
public:
remoteNetworkClient(const std::string &name, const std::string &serverAddress)
: client(name), _serverAddress(serverAddress)
{
_gmshClient = new GmshClient();
if(_gmshClient->Connect(_serverAddress.c_str()) < 0){
delete _gmshClient;
_gmshClient = 0;
}
else{
_gmshClient->Start();
}
}
virtual ~remoteNetworkClient()
{
if(_gmshClient){
_gmshClient->Stop();
_gmshClient->Disconnect();
delete _gmshClient;
_gmshClient = 0;
}
}
GmshClient *getGmshClient(){ return _gmshClient; }
virtual bool isNetworkClient(){ return true; }
virtual bool set(const number &p){ return _set(p); }
virtual bool set(const string &p){ return _set(p); }
virtual bool set(const function &p){ return _set(p); }
virtual bool set(const region &p){ return _set(p); }
virtual bool get(std::vector<number> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<string> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<function> &ps,
const std::string &name=""){ return _get(ps, name); }
virtual bool get(std::vector<region> &ps,
const std::string &name=""){ return _get(ps, name); }
void sendInfo(const std::string &msg)
{
if(_gmshClient) _gmshClient->Info(msg.c_str());
}
void sendWarning(const std::string &msg)
{
if(_gmshClient) _gmshClient->Warning(msg.c_str());
}
void sendError(const std::string &msg)
{
if(_gmshClient) _gmshClient->Error(msg.c_str());
}
void sendProgress(const std::string &msg)
{
if(_gmshClient) _gmshClient->Progress(msg.c_str());
}
void sendMergeFileRequest(const std::string &msg)
{
if(_gmshClient) _gmshClient->MergeFile(msg.c_str());
}
void sendParseStringRequest(const std::string &msg)
{
if(_gmshClient) _gmshClient->ParseString(msg.c_str());
}
};
}
#endif