root/library/bdm/base/user_info.cpp @ 1079

Revision 1079, 15.8 kB (checked in by smidl, 14 years ago)

Changes in merger + change in loading ARX

  • Property svn:eol-style set to native
RevLine 
[344]1//
[396]2// C++ Implementation: user_info.cpp
[344]3//
[396]4// Description: UI (user info) class for loading/saving objects from/to configuration files.
[344]5//
6//
[396]7// Author: smidl <smidl@utia.cas.cz>, (C) 2009
[344]8//
9// Copyright: See COPYING file that comes with this distribution
10//
11//
12
[345]13#include "user_info.h"
[244]14
[477]15namespace bdm {
[540]16
[737]17string UIException::format_message ( const string &reason, const string &path ) {
[1064]18    stringstream ss;
19    ss << reason;
20    ss << " Check path \"" << path << "\".";
21    return ss.str();
[540]22}
23
[394]24///////////////////////////// Class UIFile /////////////////////////////////////////////
[344]25
[477]26UIFile::UIFile() {
[344]27}
28
[477]29UIFile::UIFile ( const string &file_name ) {
[1064]30    try {
31        readFile ( file_name.c_str() );
32        // this flag has to be set AFTER each file load, that is why it is right here
33        setAutoConvert ( true );
34    } catch ( FileIOException f ) {
35        string msg = "UI error: file ";
36        msg += file_name;
37        msg += " not found.";
38        bdm_error ( msg );
39    } catch ( ParseException& P ) {
40        stringstream msg;
41        msg << "UI error: parsing error """ << P.getError() << """ in file " << file_name << " on line " <<  P.getLine() << ".";
42        bdm_error ( msg.str() );
43    }
[344]44}
45
46
[477]47void UIFile::save ( const string &file_name ) {
[1064]48    try {
49        writeFile ( file_name.c_str() );
50    } catch ( FileIOException f ) {
51        string msg = "UI error: file ";
52        msg += file_name;
53        msg += " is inacessible.";
54        bdm_error ( msg );
55    }
[357]56}
[344]57
[477]58UIFile::operator Setting&() {
[1064]59    return getRoot();
[344]60}
61
[394]62///////////////////////////// Class UI::MappedUI /////////////////////////////////////////////
63
[477]64UI::MappedUI::StringToUIMap& UI::MappedUI::mapped_strings() {
[1064]65    // this way it is ensured that there is only one instance of StringTpUIMap, and
66    // what is more, this declaration leaves its allocation/deallocation on the compiler
67    static StringToUIMap var;
68    return var;
[344]69}
70
[477]71UI::MappedUI::TypeInfoToStringMap& UI::MappedUI::mapped_type_infos() {
[1064]72    // this way it is ensured that there is only one instance of TypeInfoToStringMap, and
73    // what is more, this declaration leaves its allocation/deallocation on the compiler
74    static TypeInfoToStringMap var;
75    return var;
[351]76}
77
[477]78void UI::MappedUI::add_class ( const string &class_name, const type_info * const class_type_info, const UI* const ui ) {
[1064]79    pair< StringToUIMap::iterator, bool> inres =
80        mapped_strings().insert (
81            StringToUIMap::value_type ( class_name, ui ) );
82    if ( inres.second ) {
83        mapped_type_infos().insert (
84            TypeInfoToStringMap::value_type (
85                class_type_info, class_name ) );
86    }
[351]87}
88
[477]89void UI::MappedUI::unregistered_class_error ( const string &unregistered_class_name ) {
[1064]90    stringstream msg;
91    msg << "UI error: class " + unregistered_class_name + " was not properly registered. Use the macro ""UIREGISTER([class name]);"" within your code." << endl;
[394]92
[1064]93    if ( mapped_strings().size() ) {
94        StringToUIMap::const_iterator iter = mapped_strings().begin();
95        msg << "These classes are already registered: " << iter->first;
96        for ( iter++; iter != mapped_strings().end(); iter++ )
97            msg << ", " << iter->first;
98        msg << "." << endl;
99    } else
100        msg << "There is not any registered class yet!" << endl;
[477]101
[1064]102    bdm_error ( msg.str() );
[394]103}
104
[477]105const UI& UI::MappedUI::retrieve_ui ( const string &class_name ) {
[1064]106    StringToUIMap::const_iterator iter = mapped_strings().find ( class_name );
107    if ( iter == mapped_strings().end() )
108        unregistered_class_error ( class_name );
[477]109
[1064]110    return *iter->second;
[357]111}
[351]112
[477]113const string& UI::MappedUI::retrieve_class_name ( const type_info * const class_type_info ) {
[1064]114    TypeInfoToStringMap::const_iterator iter = mapped_type_infos().find ( class_type_info );
115    if ( iter == mapped_type_infos().end() )
116        unregistered_class_error ( "with RTTI name " + string ( class_type_info->name() ) );
117    return iter->second;
[357]118}
[351]119
[396]120///////////////////////////// Class SettingResolver /////////////////////////////////////////////
[351]121
[477]122SettingResolver::SettingResolver ( const Setting &potential_link )
[1064]123    : result ( initialize_reference ( file, potential_link ) ) {
[377]124}
[351]125
[477]126const Setting& SettingResolver::initialize_reference ( UIFile *&file, const Setting &potential_link ) {
[1064]127    file = NULL;
[384]128
[1064]129    if ( potential_link.getType() !=  Setting::TypeString )
130        return potential_link;
[377]131
[1064]132    string link = ( const char* ) potential_link;
133    size_t aerobase = link.find ( '@' );
[477]134
[1064]135    const Setting *result;
136    if ( aerobase != string::npos ) {
137        string file_name = link.substr ( aerobase + 1, link.length() );
138        file = new UIFile ( file_name );
139        result = & ( Setting& ) ( *file );
140        link = link.substr ( 0, aerobase );
141    } else {
142        result = &potential_link;
143        while ( !result->isRoot() )
144            result = &result->getParent();
145    }
[351]146
[1064]147    if ( !result->exists ( link ) )
148        throw UISettingException ( "UIException: linked setting was not found.", string ( ( const char* ) potential_link ) );
[351]149
[1064]150    return ( *result ) [link];
[351]151}
152
[477]153SettingResolver::~SettingResolver() {
[1064]154    if ( file ) delete file;
[351]155}
156
[394]157///////////////////////////// Class UI /////////////////////////////////////////////
[351]158
[477]159void UI::assert_type ( const Setting &element, Setting::Type type ) {
[1064]160    if ( element.getType() != type )
161        throw UISettingException ( "UIException: wrong setting type.", element );
[357]162}
[351]163
[477]164const Setting& UI::to_child_setting ( const Setting &element, const int index ) {
[1064]165    if ( !element.isList() )
166        throw UISettingException ( "UIException: only TypeList elements could be indexed by integers.", element );
[394]167
[1064]168    return element[index];
[394]169}
170
[477]171const Setting& UI::to_child_setting ( const Setting &element, const string &name ) {
[1064]172    if ( !element.isGroup() )
173        throw UISettingException ( "UIException: only TypeGroup elements could be indexed by strings.", element );
[394]174
[1064]175    return element[name];
[394]176}
177
[942]178void UI::call_to_setting( const root &instance, Setting &set, string class_name ) {
[1064]179    try {
180        instance.to_setting ( set );
181    } catch ( SettingException &sttng_xcptn ) {
182        string msg = "UIException: method ";
183        msg += class_name;
184        msg += ".to_setting(Setting&) has thrown a SettingException.";
185        throw UISettingException ( msg, sttng_xcptn.getPath() );
186    }
[942]187}
188
189void UI::save ( const root &instance, Setting &element, const string &name ) {
[1064]190    Setting &set = ( name == "" ) ?  (element.getType()==Setting::TypeArray || element.getType()==Setting::TypeList) ? element.add ( Setting::TypeGroup ) : element
191               : element.add ( name, Setting::TypeGroup );
[942]192
[1064]193    call_to_setting( instance, set );
[942]194}
195
[959]196void UI::save ( const log_level_base &log_level, Setting &element ) {
[1064]197    assert_type ( element, Setting::TypeGroup );
198    string name = "log_level";
199
200    if( element.exists( name ) )
201        assert_type ( element[name], Setting::TypeString );
202    else
203        element.add ( name, Setting::TypeString );
204
205    call_to_setting( log_level, element[name] );
[959]206}
207
[942]208void UI::save ( const root * const instance, Setting &element, const string &name ) {
[1064]209    Setting &set = ( name == "" ) ?  (element.getType()==Setting::TypeArray || element.getType()==Setting::TypeList) ? element.add ( Setting::TypeGroup ) : element
210               : element.add ( name, Setting::TypeGroup );
[942]211
[1064]212    // add attribute "class"
213    const string &class_name = MappedUI::retrieve_class_name ( &typeid ( *instance ) );
214    Setting &type = set.add ( "class", Setting::TypeString );
215    type = class_name;
[942]216
[1064]217    call_to_setting( *instance, set, class_name );
[942]218}
219
[477]220void UI::save ( const int &integer, Setting &element, const string &name ) {
[1064]221    Setting &set = ( name == "" ) ? element.add ( Setting::TypeInt )
222                   : element.add ( name, Setting::TypeInt );
223    set = integer;
[394]224}
225
[477]226void UI::save ( const double &real, Setting &element, const string &name ) {
[1064]227    Setting &set = ( name == "" ) ? element.add ( Setting::TypeFloat )
228                   : element.add ( name, Setting::TypeFloat );
229    set = real;
[394]230}
231
[477]232void UI::save ( const string &str, Setting &element, const string &name ) {
[1064]233    Setting &set = ( name == "" ) ? element.add ( Setting::TypeString )
234                   : element.add ( name, Setting::TypeString );
235    set = str;
[351]236}
237
[477]238void UI::save ( const mat &matrix, Setting &element, const string &name ) {
[1064]239    Setting &set = ( name == "" ) ? element.add ( Setting::TypeList )
240                   : element.add ( name, Setting::TypeList );
[351]241
[1064]242    Setting &tag = set.add ( Setting::TypeString );
243    tag = "matrix";
[737]244
[1064]245    Setting &rows = set.add ( Setting::TypeInt );
246    rows = matrix.rows();
[351]247
[1064]248    Setting &cols = set.add ( Setting::TypeInt );
249    cols = matrix.cols();
[357]250
[1064]251    Setting &elements = set.add ( Setting::TypeArray );
252
253    // build matrix row-wise
254    for ( int i = 0; i < matrix.rows(); i++ )
255        for ( int j = 0; j < matrix.cols(); j++ ) {
256            Setting &new_field = elements.add ( Setting::TypeFloat );
257            new_field = matrix ( i, j );
258        }
[351]259}
260
[1015]261void UI::save ( const ldmat &matrix, Setting &element, const string &name ) {
[1064]262    Setting &set = ( name == "" ) ? element.add ( Setting::TypeGroup)
263                   : element.add ( name, Setting::TypeGroup );
264
265    save (matrix._L(), set, "L");
266    save (matrix._D(), set, "D");
[1015]267}
268
[477]269void UI::save ( const ivec &vector, Setting &element, const string &name ) {
[1064]270    Setting &set = ( name == "" ) ? element.add ( Setting::TypeArray )
271                   : element.add ( name, Setting::TypeArray );
272    for ( int i = 0; i < vector.length(); i++ ) {
273        Setting &new_field = set.add ( Setting::TypeInt );
274        new_field = vector ( i );
275    }
[351]276}
277
[477]278void UI::save ( const vec &vector, Setting &element, const string &name ) {
[1064]279    Setting &set = ( name == "" ) ? element.add ( Setting::TypeArray )
280                   : element.add ( name, Setting::TypeArray );
281    for ( int i = 0; i < vector.length(); i++ ) {
282        Setting &new_field = set.add ( Setting::TypeFloat );
283        new_field = vector ( i );
284    }
[357]285}
286
[907]287
[942]288void UI::call_from_setting( root &instance, const Setting &set, string class_name) {
[1064]289    try {
290        instance.from_setting ( set );
291    } catch ( SettingException &sttng_xcptn ) {
292        string msg = "UIException: method ";
293        msg += class_name;
294        msg += ".from_setting(Setting&) has thrown a SettingException.";
295        throw UISettingException ( msg, sttng_xcptn.getPath() );
296    } catch ( std::runtime_error &e ) {
297        string msg = "UIException: method ";
298        msg += class_name;
299        msg += " says: ";
300        msg += e.what();
301        throw UISettingException ( msg, set );
302    }
[907]303
[1064]304    // validate the new instance
305    instance.validate();
[942]306}
[907]307
[959]308void UI::from_setting ( log_level_base &log_level, const Setting &element ) {
[1064]309    assert_type( element, Setting::TypeString );
310    call_from_setting( log_level, element );
[959]311}
[907]312
[959]313void UI::from_setting ( root &instance, const Setting &element ) {
[1064]314    const SettingResolver link ( element );
315    assert_type( link.result, Setting::TypeGroup );
316    call_from_setting( instance, link.result);
[959]317}
318
[477]319void UI::from_setting ( mat& matrix, const Setting &element ) {
[1064]320    const SettingResolver link ( element );
[351]321
[1064]322    if ( link.result.isNumber() ) {
323        matrix.set_size ( 1, 1 );
324        matrix ( 0, 0 ) = link.result;
325        return;
326    }
[351]327
[1064]328    if ( link.result.isList() ) {
329        int data_offset;
[351]330
[1064]331        if ( link.result.getLength() == 3 )
332            data_offset = 0;
333        else if ( link.result.getLength() == 4 ) {
334            assert_type ( link.result[0], Setting::TypeString );
335            const char* elem1 = ( const char* ) link.result[0];
336            if ( ( strcmp ( elem1, "matrix" ) ) )
337                throw UISettingException ( "UIException: the setting supposed to represent a matrix element has wrong syntax.", link.result );
[351]338
[1064]339            data_offset = 1;
340        } else
341            throw UISettingException ( "UIException: the setting supposed to represent a matrix element has wrong syntax.", link.result );
[390]342
[1064]343        Setting &rows_setting = link.result[0 + data_offset];
344        Setting &cols_setting = link.result[1 + data_offset];
345        Setting &elements = link.result[2 + data_offset];
[390]346
[1064]347        // vvv ----- not working in matlab!!
348        //assert_type ( cols_setting, Setting::TypeInt );
349        //assert_type ( rows_setting, Setting::TypeInt );
350        //assert_type ( elements, Setting::TypeArray );
[351]351
[1064]352        int cols = cols_setting;
353        int rows = rows_setting;
354        int elems = elements.getLength();
[351]355
[1064]356        if ( cols < 0 || rows < 0 )
357            throw UISettingException ( "UIException: the dimensions of a matrix has to be non-negative.", link.result );
[351]358
[1064]359        if ( elems != cols * rows )
360            throw UISettingException ( "UIException: the count of the matrix elements is incompatible with matrix dimension.", elements );
[351]361
[1064]362        matrix.set_size ( rows, cols );
[351]363
[1064]364        if ( cols == 0 || rows == 0 )
365            return;
[351]366
[1064]367        if ( !elements[0].isNumber() )
368            throw UISettingException ( "UIException: matrix elements have to be numbers.", elements[0] );
[351]369
[1064]370        // build matrix row-wise
371        int k = 0;
372        for ( int i = 0; i < rows; i++ )
373            for ( int j = 0; j < cols; j++ )
374                matrix ( i, j ) = elements[k++];
375        return;
376    }
[357]377
[1064]378    throw UISettingException ( "UIException: only numeric types or TypeList are supported as matrix values.", link.result );
[351]379}
380
[1015]381void UI::from_setting ( ldmat& matrix, const Setting &element ) {
[1064]382    if(element.exists("L")) {
383        UI::from_setting(matrix.__L(), element["L"]);
[1079]384        } else { 
385                throw  UISettingException ( "UIException: ldmat must contain matrix L.", element);
386        }
[1064]387    if(element.exists("D")) {
388        UI::from_setting(matrix.__D(), element["D"]);
[1079]389    } else {
390                throw  UISettingException ( "UIException: ldmat must contain vector D.", element);
391        }
[1064]392    matrix.validate();
[1015]393}
394
[477]395void UI::from_setting ( vec &vector, const Setting &element ) {
[1064]396    const SettingResolver link ( element );
[351]397
[1064]398    if ( link.result.isNumber() ) {
399        vector.set_length ( 1 );
400        vector ( 0 ) = link.result;
401        return;
402    }
[351]403
[1064]404    if ( link.result.isList() ) {
405        mat matrix;
406        from_setting ( matrix, link.result );
[351]407
[1064]408        if ( matrix.cols() != 1 && matrix.rows() != 1 && matrix.cols() != 0 )
409            throw UISettingException ( "UIException: the vector length is invalid, it seems to be rather a matrix.", link.result );
[351]410
[1064]411        int len = matrix.rows() * matrix.cols();
412        vector.set_length ( len );
413        if ( len == 0 ) return;
[357]414
[1064]415        if ( matrix.cols() == 1 )
416            for ( int i = 0; i < len; i++ )
417                vector ( i ) = matrix ( i, 0 );
418        else
419            for ( int i = 0; i < len; i++ )
420                vector ( i ) = matrix ( 0, i );
421        return;
422    }
[357]423
[1064]424    if ( link.result.isArray() ) {
425        int len = link.result.getLength();
426        vector.set_length ( len );
427        if ( len == 0 ) return;
[357]428
[1064]429        if ( !link.result[0].isNumber() )
430            throw UISettingException ( "UIException: a vector element has to be a number.", link.result[0] );
[357]431
[1064]432        for ( int i = 0; i < len; i++ )
433            vector ( i ) = link.result[i];
[377]434
[1064]435        return;
436    }
[357]437
[1064]438    throw UISettingException ( "UIException: only numeric types, TypeArray or TypeList are supported as vector values.", link.result );
[351]439}
440
[477]441void UI::from_setting ( ivec &vector, const Setting &element ) {
[1064]442    vec double_vector;
443    from_setting ( double_vector, element );
444    int len = double_vector.length();
445    vector.set_length ( len );
446    for ( int i = 0; i < len; i++ )
447        vector ( i ) = ( int ) double_vector ( i );
[396]448}
449
[477]450void UI::from_setting ( string &str, const Setting &element ) {
[1064]451    assert_type ( element, Setting::TypeString );
452    str = ( const char* ) element;
[357]453}
[351]454
[477]455void UI::from_setting ( int &integer, const Setting &element ) {
[490]456//      assert_type ( element, Setting::TypeInt );
[1064]457    integer = element;
[351]458}
459
[477]460void UI::from_setting ( double &real, const Setting &element ) {
[490]461//      assert_type ( element, Setting::TypeFloat );
[1064]462    real = element;
[351]463}
464
[762]465}//namespace
Note: See TracBrowser for help on using the browser.