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

Revision 416, 11.3 kB (checked in by vbarta, 15 years ago)

fixed typo (bitwise to logical or and and)

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