1 // sidattrutil.h - Classes to manage lists of component attributes and
2 // mappings between application objects and their string
3 // representations. -*- C++ -*-
5 // Copyright (C) 1999, 2000 Red Hat.
6 // This file is part of SID and is licensed under the GPL.
7 // See the file COPYING.SID for conditions for redistribution.
12 #include <sidconfig.h>
20 // XXX: kludge for compatibility both with old & new libstdc++
22 #define STDCTYPE(func) std::func
24 #define STDCTYPE(func) func
31 #ifdef HAVE_EXT_HASH_MAP
32 #include <ext/hash_map>
33 #define HAVE_HASHING 1
37 #define HAVE_HASHING 1
45 #elif HAVE_STRSTREAM_H
46 #include <strstream.h>
48 #error "need <sstream> or <strstream.h>!"
57 // Make a string from an object by the default output-streaming operator.
58 template <typename Type>
60 make_attribute (const Type& value)
63 std::ostringstream stream;
66 #elif HAVE_STRSTREAM_H
69 std::string result (stream.str (), stream.pcount ());
73 #error "need <sstream> or <strstream.h>!"
78 // Attempt to make object from a string using the default input-streaming operator.
79 template <typename Type>
80 static sid::component::status
81 parse_attribute (const std::string& str, Type& value)
84 std::istringstream stream (str);
86 #elif HAVE_STRSTREAM_H
87 istrstream stream (str.data (), str.length ());
90 #error "need <sstream> or <strstream.h>!"
93 // Ensure stream is still good, and that operator>> has consumed entire string.
94 if (! stream.bad () && (stream.rdbuf ()->in_avail () == 0))
95 return sid::component::ok;
97 return sid::component::bad_value;
102 // ---------------------------------------------------------------------------
104 // Specific attribute make/parse routines for common types
106 // Specialization for strings
108 make_attribute (const std::string& value)
113 static sid::component::status
114 parse_attribute (const std::string& str, std::string& value)
117 return sid::component::ok;
121 // Specialization for bools
123 make_attribute (const bool& value)
131 static sid::component::status
132 parse_attribute (const std::string& str, bool& value)
134 if (str == "yes" || str == "y" ||
135 str == "true" || str == "t" ||
140 return sid::component::ok;
142 else if (str == "no" || str == "n" ||
143 str == "false" || str == "f" ||
148 return sid::component::ok;
151 return sid::component::bad_value;
155 // Specialization for host_int_X
157 template <typename Value>
159 make_numeric_attribute (const Value& value, std::ios::fmtflags ios_flags = std::ios::dec)
162 std::ostringstream stream;
163 stream.flags (ios_flags);
165 return stream.str ();
166 #elif HAVE_STRSTREAM_H
168 stream.flags (ios_flags);
170 std::string result (stream.str (), stream.pcount ());
174 #error "need <sstream> or <strstream.h>!"
180 make_attribute (const sid::host_int_8& value)
182 return sidutil::make_numeric_attribute (value);
186 make_attribute (const sid::host_int_4& value)
188 return sidutil::make_numeric_attribute (value);
192 make_attribute (const sid::host_int_2& value)
194 return sidutil::make_numeric_attribute (value);
198 make_attribute (const sid::host_int_1& value)
200 // widen to avoid representation as char
201 return sidutil::make_numeric_attribute (sid::host_int_2(value));
205 make_attribute (const sid::signed_host_int_8& value)
207 return sidutil::make_numeric_attribute (value);
211 make_attribute (const sid::signed_host_int_4& value)
213 return sidutil::make_numeric_attribute (value);
217 make_attribute (const sid::signed_host_int_2& value)
219 return sidutil::make_numeric_attribute (value);
223 make_attribute (const sid::signed_host_int_1& value)
225 // widen to avoid representation as char
226 return sidutil::make_numeric_attribute (sid::signed_host_int_2(value));
230 template <typename unsignedValue>
231 static sid::component::status
232 parse_unsigned_numeric_attribute (const std::string& str, unsignedValue& value)
234 // Algorithm based on newlib's strtoul, from BSD.
236 unsignedValue base = 10;
237 unsigned parseoffset = 0;
238 bool negative = false;
240 if (str.length () == 0)
241 return sid::component::bad_value;
243 if (str.length () > parseoffset+1 && str.substr (parseoffset,1) == "-")
249 // NB: check longest prefixes first!
250 if (str.length () > parseoffset+2 && (str.substr (parseoffset,2) == "0x" ||
251 str.substr (parseoffset,2) == "0X"))
256 else if (str.length () > parseoffset+2 && (str.substr (parseoffset,2) == "0b" ||
257 str.substr (parseoffset,2) == "0B"))
262 else if (str.length () > parseoffset+1 && str.substr (parseoffset,1) == "0")
268 //cout << "str=" << str << " base=" << base << " negative=" << negative;
270 unsignedValue acc = 0;
271 unsignedValue max = (unsignedValue) -1;
272 unsignedValue cutoff = max / base;
273 unsignedValue cutlim = max % base;
274 for (unsigned i = parseoffset; i < str.length (); i++)
276 unsigned char c = str[i];
277 // cout << "c=" << (int)c << " acc=" << acc << endl;
278 if (STDCTYPE(isdigit) (c))
280 else if (STDCTYPE(isalpha) (c))
281 c -= STDCTYPE(isupper) (c) ? 'A' - 10 : 'a' - 10;
283 return sid::component::bad_value;
285 // limit accumulation
287 return sid::component::bad_value;
288 else if (acc > cutoff || (acc == cutoff && c > cutlim))
289 return sid::component::bad_value;
295 value = negative ? -acc : acc;
296 // cout << " value=" << value << endl;
298 return sid::component::ok;
302 static sid::component::status
303 parse_attribute (const std::string& str, sid::host_int_8& value)
305 return sidutil::parse_unsigned_numeric_attribute (str, value);
308 static sid::component::status
309 parse_attribute (const std::string& str, sid::host_int_4& value)
311 return sidutil::parse_unsigned_numeric_attribute (str, value);
314 static sid::component::status
315 parse_attribute (const std::string& str, sid::host_int_2& value)
317 return sidutil::parse_unsigned_numeric_attribute (str, value);
320 static sid::component::status
321 parse_attribute (const std::string& str, sid::host_int_1& value)
323 return sidutil::parse_unsigned_numeric_attribute (str, value);
327 // ??? The unsigned versions don't mark negative values as bad so
328 // for now the signed versions don't mark big unsigned values as bad.
330 static sid::component::status
331 parse_attribute (const std::string& str, sid::signed_host_int_8& value)
333 sid::host_int_8 uvalue;
334 sid::component::status s = sidutil::parse_unsigned_numeric_attribute (str, uvalue);
335 if (s == sid::component::ok)
340 static sid::component::status
341 parse_attribute (const std::string& str, sid::signed_host_int_4& value)
343 sid::host_int_4 uvalue;
344 sid::component::status s = sidutil::parse_unsigned_numeric_attribute (str, uvalue);
345 if (s == sid::component::ok)
350 static sid::component::status
351 parse_attribute (const std::string& str, sid::signed_host_int_2& value)
353 sid::host_int_2 uvalue;
354 sid::component::status s = sidutil::parse_unsigned_numeric_attribute (str, uvalue);
355 if (s == sid::component::ok)
360 static sid::component::status
361 parse_attribute (const std::string& str, sid::signed_host_int_1& value)
363 sid::host_int_1 uvalue;
364 sid::component::status s = sidutil::parse_unsigned_numeric_attribute (str, uvalue);
365 if (s == sid::component::ok)
372 // Specialization for {big,little}_int types
374 template <typename IntType, bool IsBig>
375 static sid::component::status
376 parse_attribute (const std::string& str, sid::any_int<IntType,IsBig>& value)
378 typename sid::any_int<IntType,IsBig>::value_type v;
379 sid::component::status s = parse_attribute (str, v);
380 if (s == sid::component::ok)
385 template <typename IntType, bool IsBig>
387 make_attribute (const sid::any_int<IntType,IsBig>& value)
389 typename sid::any_int<IntType,IsBig>::value_type v = value.integer_value ();
390 return make_attribute (v);
396 // ---------------------------------------------------------------------------
399 // Abstract attribute-coder class provides interface to a pair of
400 // string->object and object->string conversion functions.
401 class attribute_coder_base
404 virtual std::string make_attribute() const = 0;
405 virtual sid::component::status parse_attribute(const std::string& str) = 0;
406 virtual ~attribute_coder_base() {}
410 // This kind of attribute coder calls a pair of unparameterized
411 // member functions for making/parsing attribute strings.
412 template <class Class>
413 class attribute_coder_virtual: public attribute_coder_base
416 typedef std::string (Class::*getter_f) ();
417 typedef sid::component::status (Class::*setter_f) (const std::string&);
425 attribute_coder_virtual (Class* r, getter_f g, setter_f s):
426 receiver (r), getter (g), setter (s) {}
428 attribute_coder_virtual (Class* r, setter_f s, getter_f g):
429 receiver (r), getter (g), setter (s) {}
431 std::string make_attribute () const
432 { return (receiver->*getter) (); }
434 sid::component::status
435 parse_attribute (const std::string& str)
436 { return (receiver->*setter) (str); }
438 ~attribute_coder_virtual() { }
442 // This kind of attribute coder redirects the calls to another
443 // object's named attribute. This may be used to create
444 // aliased attributes.
445 class attribute_coder_alias: public attribute_coder_base
448 sid::component* receiver;
452 attribute_coder_alias (sid::component* r, const std::string& n):
453 receiver (r), name(n) {}
455 std::string make_attribute () const
456 { return receiver->attribute_value (name); }
458 sid::component::status
459 parse_attribute (const std::string& str)
460 { return receiver->set_attribute_value (name, str); }
462 ~attribute_coder_alias() { }
467 // This kind of attribute coder calls a pair of member functions for
468 // making/parsing attribute strings. They are parameterized with a
469 // value of some type.
470 template <class Class, typename Parameter>
471 class attribute_coder_virtual_parameterized: public attribute_coder_base
474 typedef std::string (Class::*getter_f) (Parameter);
475 typedef sid::component::status (Class::*setter_f)
476 (Parameter, const std::string&);
485 attribute_coder_virtual_parameterized (Class* r, getter_f g, setter_f s,
487 :receiver (r), getter (g), setter (s), parameter (p) { }
489 attribute_coder_virtual_parameterized (Class* r, setter_f s, getter_f g,
491 :receiver (r), getter (g), setter (s), parameter (p) { }
494 make_attribute () const
496 return (receiver->*getter) (parameter);
499 sid::component::status
500 parse_attribute (const std::string& str)
502 return (receiver->*setter) (parameter, str);
505 ~attribute_coder_virtual_parameterized() { }
510 // This attribute coder stores a pointer to a value. It forwards
511 // make_attribute and parse_attribute to the pointed-to value for
512 // mapping to/from strings.
513 template <typename Value>
514 class attribute_coder: public attribute_coder_base
518 attribute_coder (Value* p): ptr (p) {}
520 std::string make_attribute () const
522 return sidutil::make_attribute (*ptr);
525 sid::component::status parse_attribute (const std::string& str)
527 return sidutil::parse_attribute (str, *ptr);
530 ~attribute_coder() { }
534 // This attribute coder stores a pointer to a value. It forwards
535 // make_attribute to the pointed-to value for mapping from
536 // strings. It intercepts parse_attribute to prevent a value change.
537 template <typename Value>
538 class attribute_coder_ro: public attribute_coder<Value>
541 attribute_coder_ro (Value* p): attribute_coder<Value> (p) {}
543 // Override to disable writing.
544 sid::component::status
545 parse_attribute (const std::string& str)
547 return sid::component::bad_value;
550 ~attribute_coder_ro() { }
554 // This attribute coder stores a literal const value. It forwards
555 // make_attribute to the value for mapping from strings. It
556 // intercepts parse_attribute to prevent a value change.
557 template <typename Value>
558 class attribute_coder_ro_value: public attribute_coder_base
563 attribute_coder_ro_value (const Value& v): value (v) {}
565 std::string make_attribute () const
567 return sidutil::make_attribute (value);
570 sid::component::status parse_attribute (const std::string& str)
572 return sid::component::bad_value;
575 ~attribute_coder_ro_value() { }
580 // This attribute coder is like basic attribute_coder<>, but it
581 // calls a notification function after any parse_attribute attempt.
582 template <typename Value, class Class>
583 class attribute_coder_notify: public attribute_coder<Value>
585 typedef void (Class::*Callback) ();
590 attribute_coder_notify (Value* p, Class* rec, Callback f):
591 attribute_coder<Value> (p), receiver (rec), pmf (f) {}
593 sid::component::status
594 parse_attribute (const std::string& str)
596 sid::component::status stat =
597 attribute_coder<Value>::parse_attribute (str);
598 // XXX: make sense to call pmf if stat != ok?
599 // XXX: could even endavour to restore previous value if != ok
606 // This attribute coder class performs its work by reading/writing
607 // a fixed address via a bus.
608 template <class DataType>
609 class attribute_coder_bus_rw: public attribute_coder_base
611 mutable sid::bus* target;
612 sid::host_int_4 address;
615 attribute_coder_bus_rw (sid::bus* t, sid::host_int_4 a)
616 : target (t), address (a)
621 std::string make_attribute () const
624 sid::bus::status s2 = this->target->read (address, value);
625 if (s2 == sid::bus::ok) return sidutil::make_attribute (value);
629 sid::component::status parse_attribute (const std::string& str)
632 sid::component::status s1 = sidutil::parse_attribute (str, value);
633 if (s1 != sid::component::ok) return s1;
634 sid::bus::status s2 = this->target->write (address, value);
635 if (s2 == sid::bus::ok) return sid::component::ok;
636 else return sid::component::bad_value;
639 ~attribute_coder_bus_rw() { }
643 // This is a read-only variety of the same thing.
644 template <class DataType>
645 class attribute_coder_bus_ro: public attribute_coder_bus_rw<DataType>
648 attribute_coder_bus_ro (sid::bus* t, sid::host_int_4 a):
649 attribute_coder_bus_rw<DataType> (t, a) {}
651 sid::component::status parse_attribute (const std::string& str)
653 return sid::component::bad_value;
658 // This is a write-only variety of the same thing. It returns the
659 // last successfully written value on reads.
660 template <class DataType>
661 class attribute_coder_bus_wo: public attribute_coder_bus_rw<DataType>
664 attribute_coder_bus_wo (sid::bus* t, sid::host_int_4 a):
665 attribute_coder_bus_rw<DataType> (t, a),
666 last_written_attribute ("no value")
669 std::string make_attribute () const
671 return this->last_written_attribute;
674 sid::component::status parse_attribute (const std::string& str)
676 sid::component::status s = attribute_coder_bus_rw<DataType>::parse_attribute (str);
677 if (s == sid::component::ok)
678 this->last_written_attribute = str;
682 ~attribute_coder_bus_wo() { }
685 std::string last_written_attribute;
693 operator () (const std::string& s) const
696 return std::hash<const char*> () (s.c_str ());
702 // A mix-in for classes with largely static attribute lists.
703 class fixed_attribute_map_component: public virtual sid::component
706 // use hash table for this, if available
708 typedef std::hash_map<std::string,attribute_coder_base*,hash_string> attribute_map_t;
710 typedef std::map<std::string,attribute_coder_base*> attribute_map_t;
712 mutable attribute_map_t attribute_map;
715 // map attribute name <-> category name
717 // Each matching entry in these parallel lists represents one
718 // attribute name <-> category name relationship.
719 std::vector<std::string> category_pair_attribute;
720 std::vector<std::string> category_pair_category;
722 // XXX: This used to be a pair of string->set<string> maps, but
723 // the compiler working set blew up.
726 ~fixed_attribute_map_component () { /* XXX: delete coder objects */ }
728 // Add or remove an attribute <-> category association. The named
729 // attribute must already exist.
731 categorize (const std::string& attr, const std::string& category)
733 assert (this->attribute_map.find (attr) != this->attribute_map.end ());
735 // Add a matching pair into the category_pair vectors.
736 this->category_pair_attribute.push_back (attr);
737 this->category_pair_category.push_back (category);
739 // size of both vectors should be same
740 assert (this->category_pair_attribute.size () ==
741 this->category_pair_category.size ());
745 // Remove all entry pairs from the category_pair vectors where the
746 // attribute name matches the argument attr.
748 uncategorize (const std::string& attr)
750 assert (this->attribute_map.find (attr) != this->attribute_map.end ());
752 // Remove all entry pairs from the category_pair vectors where
753 // the attribute name matches.
756 while (i < this->category_pair_attribute.size ())
758 if (this->category_pair_attribute[i] == attr)
760 this->category_pair_attribute.erase (
761 this->category_pair_attribute.begin () + i);
763 this->category_pair_category.erase (
764 this->category_pair_category.begin () + i );
770 assert (this->category_pair_attribute.size () ==
771 this->category_pair_category.size ());
775 // Low level add-attribute: supply associated coder instance
776 // XXX: candidates for moving out-of-line
778 add_attribute_coder (const std::string& name,
779 attribute_coder_base* coder_ptr)
781 assert (this->attribute_map.find (name) == this->attribute_map.end ());
782 this->attribute_map[name] = coder_ptr;
787 add_attribute_coder (const std::string& name,
788 attribute_coder_base* coder_ptr,
789 const std::string& category)
791 this->add_attribute_coder (name, coder_ptr);
792 this->categorize (name, category);
795 // Add basic attribute; use streaming conversions
796 template <typename Value>
798 add_attribute (const std::string& name, Value* ptr)
800 this->add_attribute_coder (name, new attribute_coder<Value> (ptr));
804 template <typename Value>
806 add_attribute (const std::string& name, Value* ptr,
807 const std::string& category)
809 this->add_attribute (name, ptr);
810 this->categorize (name, category);
813 // Add read-only attribute
814 template <typename Value>
816 add_attribute_ro (const std::string& name, Value* str_ptr)
818 this->add_attribute_coder (name,
819 new attribute_coder_ro<Value> (str_ptr));
822 template <typename Value>
824 add_attribute_ro (const std::string& name, Value* str_ptr,
825 const std::string& category)
827 this->add_attribute_ro (name, str_ptr);
828 this->categorize (name, category);
832 // Add read-only value attribute
833 template <typename Value>
835 add_attribute_ro_value (const std::string& name, const Value& v)
837 this->add_attribute_coder (name,
838 new attribute_coder_ro_value<Value> (v));
842 template <typename Value>
844 add_attribute_ro_value (const std::string& name, const Value& v,
845 const std::string& category)
847 this->add_attribute_ro_value (name, v);
848 this->categorize (name, category);
851 // Add an attribute alias
853 add_attribute_alias (const std::string& aka, const std::string& name)
855 this->add_attribute_coder (aka,
856 new attribute_coder_alias (this, name));
860 add_attribute_alias (const std::string& aka, const std::string& name,
861 const std::string& category)
863 this->add_attribute_alias (aka, name);
864 this->categorize (name, category);
868 // Add a r/w attribute. After a write, call given function.
869 template <typename Value, class Class>
871 add_attribute_notify (const std::string& name, Value* str_ptr,
873 void (Class::*pmf) ())
875 this->add_attribute_coder (name,
876 new attribute_coder_notify<Value,Class>
877 (str_ptr, receiver, pmf));
880 template <typename Value, class Class>
882 add_attribute_notify (const std::string& name, Value* str_ptr,
884 void (Class::*pmf) (),
885 const std::string& category)
887 this->add_attribute_notify (name, str_ptr, receiver, pmf);
888 this->categorize (name, category);
892 // Add a r/w attribute. Use given functions for getting/setting values.
893 template <class Class, typename Getter, typename Setter>
895 add_attribute_virtual (const std::string& name,
900 this->add_attribute_coder (name,
901 new attribute_coder_virtual<Class> (receiver,
906 template <class Class, typename Getter, typename Setter>
908 add_attribute_virtual (const std::string& name,
912 const std::string& category)
914 this->add_attribute_virtual (name, receiver, getter, setter);
915 this->categorize (name, category);
918 // Add a parameterized r/w attribute. Use given functions for getting/setting values.
919 template <class Class, typename Getter, typename Setter, typename Parameter>
921 add_attribute_virtual_parameterized (const std::string& name,
927 this->add_attribute_coder (name,
928 new attribute_coder_virtual_parameterized<Class,Parameter>
936 template <class Class, typename Getter, typename Setter, typename Parameter>
938 add_attribute_virtual_parameterized (const std::string& name,
943 const std::string& category)
945 this->add_attribute_virtual_parameterized (name,
950 this->categorize (name, category);
955 // Removes attribute name from component.
957 remove_attribute (const std::string& name)
959 assert (this->attribute_map.find (name) != this->attribute_map.end ());
960 this->uncategorize (name);
961 this->attribute_map.erase (name);
962 // XXX: delete coder?
967 // Returns vector containing names of all component's attributes.
968 std::vector<std::string>
969 attribute_names () throw()
971 std::vector<std::string> names;
972 for (attribute_map_t::const_iterator it =
973 this->attribute_map.begin();
974 it != this->attribute_map.end();
977 names.push_back ((*it).first);
982 // Method returns the names of a component's attribute in a given
984 std::vector<std::string>
985 attribute_names (const std::string& category) throw()
987 std::vector<std::string> attrs;
988 for (unsigned i= 0; i< this->category_pair_category.size(); i++)
990 if (this->category_pair_category[i] == category)
991 attrs.push_back (this->category_pair_attribute[i]);
996 // Method returns attribute value corresponding to attribute name
997 // passed as argument. Method returns value in std::string form
998 // using make_atribute method.
1000 attribute_value (const std::string& name) throw()
1002 attribute_map_t::iterator it = this->attribute_map.find(name);
1003 if (it == this->attribute_map.end())
1006 return ((*it).second)->make_attribute ();
1010 // Method sets attribute value corresponding to attribute name (arg. 1).
1011 // The value of attribute is set by parsing argument value using
1012 // parse_attribute method. Method returns ok if value is set.
1014 set_attribute_value (const std::string& name,
1015 const std::string& value) throw()
1017 attribute_map_t::iterator it = this->attribute_map.find (name);
1018 if (it == this->attribute_map.end ())
1019 return component::not_found;
1021 return ((*it).second)->parse_attribute (value);
1026 #endif // SIDATTRUTIL_H