Siena Simplification Library Documentation (v. 1.1.4) |
00001 // -*- C++ -*- 00002 // 00003 // This file is part of Siena, a wide-area event notification system. 00004 // See http://www.cs.colorado.edu/serl/siena/ 00005 // 00006 // Authors: See the file AUTHORS for full details. 00007 // 00008 // Copyright (C) 2002-2004 University of Colorado 00009 // 00010 // This program is free software; you can redistribute it and/or 00011 // modify it under the terms of the GNU General Public License 00012 // as published by the Free Software Foundation; either version 2 00013 // of the License, or (at your option) any later version. 00014 // 00015 // This program is distributed in the hope that it will be useful, 00016 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00018 // GNU General Public License for more details. 00019 // 00020 // You should have received a copy of the GNU General Public License 00021 // along with this program; if not, write to the Free Software 00022 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, 00023 // USA, or send email to [email protected]. 00024 // 00025 // $Id: ssimp_types.h,v 1.8 2006/05/05 13:53:47 carzanig Exp $ 00026 // 00027 #ifndef SIMP_TYPES_H 00028 #define SIMP_TYPES_H 00029 00030 #include <map> 00031 #include <set> 00032 #include <sstream> 00033 #include <string> 00034 #include "siena/simplify.h" 00035 00046 class Constraint : public siena::constraint 00047 { 00048 class Value 00049 { 00050 public: 00051 Value( bool b ) 00052 : m_type( siena::bool_id ), m_bool( b ), 00053 m_bytesize( sizeof( siena::type_id ) + sizeof( bool ) ) {} 00054 00055 Value( double d ) 00056 : m_type( siena::double_id ), m_double( d ), 00057 m_bytesize( sizeof( siena::type_id ) + sizeof( double ) ) {} 00058 00059 Value( int i ) 00060 : m_type( siena::int_id ), m_int( i ), 00061 m_bytesize( sizeof( siena::type_id ) + sizeof( int ) ) {} 00062 00063 Value( const std::string& s ) 00064 : m_type( siena::string_id ), m_string( s ), 00065 m_bytesize( sizeof( siena::type_id ) + s.length() ) {} 00066 00067 Value() 00068 : m_type( siena::anytype_id ), m_int( 0 ), 00069 m_bytesize( sizeof( siena::type_id ) ) {} 00070 00071 Value( const Value& v ) 00072 { 00073 m_type = v.m_type; 00074 switch( m_type ) 00075 { 00076 case siena::bool_id: m_bool = v.m_bool; break; 00077 case siena::double_id: m_double = v.m_double; break; 00078 case siena::anytype_id: 00079 case siena::int_id: m_int = v.m_int; break; 00080 default: m_string = v.m_string; 00081 } 00082 m_bytesize = v.m_bytesize; 00083 } 00084 00085 const Value& operator= ( const Value& v ) 00086 { 00087 m_type = v.m_type; 00088 switch( m_type ) 00089 { 00090 case siena::bool_id: m_bool = v.m_bool; break; 00091 case siena::double_id: m_double = v.m_double; break; 00092 case siena::anytype_id: 00093 case siena::int_id: m_int = v.m_int; break; 00094 default: m_string = v.m_string; 00095 } 00096 m_bytesize = v.m_bytesize; 00097 return (*this); 00098 } 00099 00100 bool operator== ( const Value& v ) const 00101 { 00102 if( m_type != v.m_type ) { return false; } 00103 switch( m_type ) 00104 { 00105 case siena::bool_id: return m_bool == v.m_bool; 00106 case siena::double_id: return m_double == v.m_double; 00107 case siena::int_id: return m_int == v.m_int; 00108 case siena::anytype_id: return true; 00109 default: return m_string == v.m_string; 00110 } 00111 } 00112 00113 bool operator< ( const Value& v ) const 00114 { 00115 if( m_type != v.m_type ) { return m_type < v.m_type; } 00116 switch( m_type ) 00117 { 00118 case siena::bool_id: return m_bool < v.m_bool; 00119 case siena::double_id: return m_double < v.m_double; 00120 case siena::int_id: return m_int < v.m_int; 00121 case siena::anytype_id: return false; 00122 default: return m_string < v.m_string; 00123 } 00124 } 00125 00126 bool operator> ( const Value& v ) const 00127 { 00128 if( m_type != v.m_type ) { return m_type > v.m_type; } 00129 switch( m_type ) 00130 { 00131 case siena::bool_id: return m_bool > v.m_bool; 00132 case siena::double_id: return m_double > v.m_double; 00133 case siena::int_id: return m_int > v.m_int; 00134 case siena::anytype_id: return false; 00135 default: return m_string > v.m_string; 00136 } 00137 } 00138 00139 bool operator<= ( const Value& v ) const 00140 { 00141 if( m_type != v.m_type ) { return m_type <= v.m_type; } 00142 switch( m_type ) 00143 { 00144 case siena::bool_id: return m_bool <= v.m_bool; 00145 case siena::double_id: return m_double <= v.m_double; 00146 case siena::int_id: return m_int <= v.m_int; 00147 case siena::anytype_id: return true; 00148 default: return m_string <= v.m_string; 00149 } 00150 } 00151 00152 bool operator>= ( const Value& v ) const 00153 { 00154 if( m_type != v.m_type ) { return m_type >= v.m_type; } 00155 switch( m_type ) 00156 { 00157 case siena::bool_id: return m_bool >= v.m_bool; 00158 case siena::double_id: return m_double >= v.m_double; 00159 case siena::int_id: return m_int >= v.m_int; 00160 case siena::anytype_id: return true; 00161 default: return m_string >= v.m_string; 00162 } 00163 } 00164 00165 bool operator!= ( const Value& v ) const 00166 { 00167 if( m_type != v.m_type ) { return true; } 00168 switch( m_type ) 00169 { 00170 case siena::bool_id: return m_bool != v.m_bool; 00171 case siena::double_id: return m_double != v.m_double; 00172 case siena::int_id: return m_int != v.m_int; 00173 case siena::anytype_id: return false; 00174 default: return m_string != v.m_string; 00175 } 00176 } 00177 00178 size_t bytesize() const { return m_bytesize; } 00179 00180 siena::type_id m_type; 00181 union 00182 { 00183 bool m_bool; 00184 double m_double; 00185 int m_int; 00186 }; 00187 std::string m_string; 00188 size_t m_bytesize; 00189 }; 00190 00191 public: 00195 Constraint( const std::string& name, siena::operator_id op, siena::bool_t b ) 00196 : m_name( name ), m_op( op ), m_value( b ), 00197 m_bytesize( name.length() + sizeof( siena::operator_id ) + m_value.bytesize() ) {} 00198 00202 Constraint( const std::string& name, siena::operator_id op, siena::double_t d ) 00203 : m_name( name ), m_op( op ), m_value( d ), 00204 m_bytesize( name.length() + sizeof( siena::operator_id ) + m_value.bytesize() ) {} 00205 00209 Constraint( const std::string& name, siena::operator_id op, siena::int_t i ) 00210 : m_name( name ), m_op( op ), m_value( (int)i ), 00211 m_bytesize( name.length() + sizeof( siena::operator_id ) + m_value.bytesize() ) {} 00212 00216 Constraint( const std::string& name, siena::operator_id op, const std::string& s ) 00217 : m_name( name ), m_op( op ), m_value( s ), 00218 m_bytesize( name.length() + sizeof( siena::operator_id ) + m_value.bytesize() ) {} 00219 00222 Constraint( const std::string& name ) 00223 : m_name( name ), m_op(siena::any_id), m_value(), 00224 m_bytesize( name.length() + sizeof( siena::operator_id ) ) {} 00225 00228 Constraint( const Constraint& c ) 00229 : m_name( c.m_name ), m_op( c.m_op ), m_value( c.m_value ), 00230 m_bytesize( c.m_bytesize ) {} 00231 00234 const Constraint& operator=( const Constraint& c ) 00235 { 00236 m_name = c.m_name; m_op = c.m_op; 00237 m_value = c.m_value; m_bytesize = c.m_bytesize; 00238 return *this; 00239 } 00240 00246 bool operator==( const Constraint& c ) const 00247 { return m_name == c.m_name && m_op == c.m_op && m_value == c.m_value; } 00248 00254 bool operator<( const Constraint& c ) const 00255 { 00256 if( m_name != c.m_name ) { return m_name < c.m_name; } 00257 else if( m_op != c.m_op ) { return m_op < c.m_op; } 00258 else { return m_value < c.m_value; } 00259 } 00260 00261 ~Constraint() {} 00262 00268 siena::bool_t bool_value() const 00269 { return m_value.m_bool; } 00270 00276 siena::double_t double_value() const 00277 { return m_value.m_double; } 00278 00285 size_t bytesize() const 00286 { return m_bytesize; } 00287 00293 siena::int_t int_value() const 00294 { return m_value.m_int; } 00295 00298 siena::string_t name() const 00299 { return siena::string_t( m_name.c_str(), m_name.length() ); } 00300 00303 siena::operator_id op() const 00304 { return m_op; } 00305 00309 std::ostream& sff(std::ostream& out) const; 00310 00314 std::string str() const; 00315 00321 siena::string_t string_value() const 00322 { return siena::string_t( m_value.m_string.c_str(), m_value.m_string.length() ); } 00323 00326 siena::type_id type() const 00327 { return m_value.m_type; } 00328 00329 private: 00330 std::string m_name; 00331 siena::operator_id m_op; 00332 Value m_value; 00333 size_t m_bytesize; 00334 }; 00335 00336 inline std::ostream& operator<< ( std::ostream& out, const Constraint& c ) 00337 { return out << c.str(); } 00338 00343 template<bool Simplify> class TFilter : public siena::filter 00344 { 00345 public: 00348 class Iterator : public siena::filter::iterator 00349 { 00350 public: 00351 Iterator( std::set<Constraint>::iterator begin, std::set<Constraint>::iterator end ) 00352 : m_end( end ), m_index( begin ) {} 00353 00354 ~Iterator() {} 00355 00356 siena::bool_t bool_value() const 00357 { return (*m_index).bool_value(); } 00358 00359 siena::double_t double_value() const 00360 { return (*m_index).double_value(); } 00361 00362 siena::int_t int_value() const 00363 { return (*m_index).int_value(); } 00364 00365 siena::string_t name() const 00366 { return (*m_index).name(); } 00367 00368 bool next() 00369 { 00370 if( m_index == m_end || ++m_index == m_end ) { return false; } 00371 else { return true; } 00372 } 00373 00374 siena::operator_id op() const 00375 { return (*m_index).op(); } 00376 00377 std::ostream& sff(std::ostream& out) const; 00378 00379 std::string str() const 00380 { return (*m_index).str(); } 00381 00382 siena::string_t string_value() const 00383 { return (*m_index).string_value(); } 00384 00385 siena::type_id type() const 00386 { return (*m_index).type(); } 00387 00388 private: 00389 std::set<Constraint>::iterator m_end; 00390 std::set<Constraint>::iterator m_index; 00391 }; 00392 00393 TFilter() 00394 : m_conflicted( false ), m_bytesize( 0 ) {} 00395 00396 ~TFilter() {} 00397 00398 TFilter( const TFilter& f ) 00399 : m_conflicted( f.m_conflicted ), m_constraints( f.m_constraints ), 00400 m_bytesize( f.m_bytesize ) {} 00401 00402 const TFilter& operator=( const TFilter& f ) 00403 { 00404 m_conflicted = f.m_conflicted; 00405 m_constraints = f.m_constraints; 00406 m_bytesize = f.m_bytesize; 00407 return (*this); 00408 } 00409 00410 bool operator<( const TFilter& f ) const 00411 { 00412 /* 00413 * not sure that the extra test with the size is necessary... 00414 */ 00415 if( m_constraints.size() != f.m_constraints.size() ) 00416 { return m_constraints.size() < f.m_constraints.size(); } 00417 return m_constraints < f.m_constraints; 00418 } 00419 00420 bool operator== ( const TFilter& f ) const 00421 { return m_constraints == f.m_constraints; } 00422 00423 void add( const Constraint& c ) 00424 { 00425 if( Simplify ) 00426 { 00427 // once a filter is conflicted there is no point in adding 00428 // constraints to it. 00429 if( m_conflicted ) 00430 { 00431 return; 00432 } 00433 std::set<Constraint>::iterator i = m_constraints.begin(); 00434 while ( i != m_constraints.end() ) 00435 { 00436 if( conflicting( (*i), c ) ) 00437 { 00438 m_conflicted = true; 00439 m_constraints.clear(); 00440 m_bytesize = 0; 00441 return; 00442 } 00443 if( siena::covers( c, (*i) ) ) 00444 { 00445 return; 00446 } 00447 if( siena::covers( (*i), c ) ) 00448 { 00449 m_bytesize -= (*i).bytesize(); 00450 m_constraints.erase( i++ ); 00451 } 00452 else 00453 { 00454 ++i; 00455 } 00456 } 00457 } 00458 if( m_constraints.insert( c ).second ) 00459 { 00460 m_bytesize += c.bytesize(); 00461 } 00462 } 00463 00464 Iterator* first() const 00465 { 00466 if( m_constraints.empty() ) { return NULL; } 00467 return new Iterator( m_constraints.begin(), m_constraints.end() ); 00468 } 00469 00470 const std::set<Constraint>& getConstraints() const 00471 { return m_constraints; } 00472 00473 size_t bytesize() const { return m_bytesize; } 00474 00475 std::ostream& sff(std::ostream& out) const 00476 { 00477 std::set<Constraint>::const_iterator i; 00478 for( i = m_constraints.begin(); i != m_constraints.end(); ++i ) 00479 { 00480 if( i != m_constraints.begin() ) 00481 { 00482 out << ", "; 00483 } 00484 (*i).sff(out); 00485 } 00486 return out; 00487 } 00488 00489 int size() const { return m_constraints.size(); } 00490 00491 std::string str() const 00492 { 00493 std::ostringstream oss; 00494 oss << "[Filter: constraints={"; 00495 std::set<Constraint>::const_iterator i; 00496 for( i = m_constraints.begin(); i != m_constraints.end(); ++i ) 00497 { 00498 if( i != m_constraints.begin() ) 00499 { 00500 oss << ","; 00501 } 00502 oss << (*i).str(); 00503 } 00504 oss << "}]"; 00505 return oss.str(); 00506 } 00507 00508 private: 00509 bool m_conflicted; 00510 std::set<Constraint> m_constraints; 00511 size_t m_bytesize; 00512 }; 00513 00514 template<bool Simplify> inline std::ostream& operator<<( std::ostream& out, const TFilter<Simplify>& f ) 00515 { return out << f.str(); } 00516 00519 typedef TFilter<false> BasicFilter; 00522 typedef TFilter<true> SimplifyingFilter; 00523 00528 template<bool Simplify> class TPredicate : public siena::predicate 00529 { 00530 public: 00531 typedef TFilter<Simplify> filter_type; 00532 typedef typename filter_type::Iterator filter_iterator; 00533 typedef typename std::set<filter_type>::iterator filter_set_iterator; 00534 typedef typename std::set<filter_type>::const_iterator const_filter_set_iterator; 00535 00538 class Iterator : public siena::predicate::iterator 00539 { 00540 public: 00541 Iterator( filter_set_iterator begin, filter_set_iterator end ) 00542 : m_end( end ), m_index( begin ) {} 00543 00544 filter_iterator* first() const 00545 { return (*m_index).first(); } 00546 00547 ~Iterator() {} 00548 00549 bool next() 00550 { 00551 if( m_index == m_end || ++m_index == m_end ) { return false; } 00552 else { return true; } 00553 } 00554 00555 std::string str() const 00556 { return (*m_index).str(); } 00557 00558 private: 00559 filter_set_iterator m_end; 00560 filter_set_iterator m_index; 00561 }; 00562 00563 TPredicate() : m_bytesize( 0 ) {} 00564 00565 TPredicate( const TPredicate& p ) 00566 : m_filters( p.m_filters ), m_bytesize( p.m_bytesize ) {} 00567 00568 ~TPredicate() {} 00569 00570 const TPredicate& operator= ( const TPredicate& p ) 00571 { 00572 m_filters = p.m_filters; 00573 m_bytesize = p.m_bytesize; 00574 return *this; 00575 } 00576 00577 bool operator== ( const TPredicate& p ) const 00578 { return m_filters == p.m_filters; } 00579 00580 void add( const TPredicate& p ); 00581 00582 void add( const filter_type& f ); 00583 00584 void clear() 00585 { m_bytesize = 0; m_filters.clear(); } 00586 00587 Iterator* first() const 00588 { 00589 if( m_filters.empty() ) { return NULL; } 00590 return new Iterator( m_filters.begin(), m_filters.end() ); 00591 } 00592 00593 size_t bytesize() const 00594 { return m_bytesize; } 00595 00596 const std::set<filter_type>& getFilters() const 00597 { return m_filters; } 00598 00599 std::ostream& sff(std::ostream& out) const; 00600 00601 int size() const 00602 { return m_filters.size(); } 00603 00604 std::string str() const; 00605 private: 00606 std::set<filter_type> m_filters; 00607 size_t m_bytesize; 00608 }; 00609 00610 template<bool Simplify> inline void TPredicate<Simplify> :: add( const TPredicate<Simplify>& p ) 00611 { 00612 const_filter_set_iterator i; 00613 for( i = p.m_filters.begin(); i != p.m_filters.end(); ++i ) 00614 { 00615 add( *i ); 00616 } 00617 } 00618 00619 template<bool Simplify> inline void TPredicate<Simplify> :: add( const TPredicate<Simplify>::filter_type& f ) 00620 { 00621 if( Simplify ) 00622 { 00623 // no point in adding empty filters 00624 if( ! f.size() ) 00625 { 00626 return; 00627 } 00628 filter_set_iterator i = m_filters.begin(); 00629 while ( i != m_filters.end() ) 00630 { 00631 if( siena::covers( (*i), f ) ) 00632 { 00633 return; 00634 } 00635 if( siena::covers( f, (*i) ) ) 00636 { 00637 m_bytesize -= (*i).bytesize(); 00638 m_filters.erase( i++ ); 00639 } 00640 else 00641 { 00642 ++i; 00643 } 00644 } 00645 } 00646 if( m_filters.insert( f ).second ) 00647 { 00648 m_bytesize += f.bytesize(); 00649 } 00650 } 00651 00652 template<bool Simplify> inline std::ostream& TPredicate<Simplify> :: sff(std::ostream& out) const 00653 { 00654 const_filter_set_iterator i; 00655 for( i = m_filters.begin(); i != m_filters.end(); ++i ) 00656 { 00657 if( i != m_filters.begin() ) 00658 { 00659 out << std::endl << " | "; 00660 } 00661 (*i).sff(out); 00662 } 00663 return out; 00664 } 00665 00666 template<bool Simplify> inline std::string TPredicate<Simplify> :: str() const 00667 { 00668 std::ostringstream oss; 00669 oss << "[Predicate: bytesize=" << m_bytesize << ",filters={"; 00670 const_filter_set_iterator i; 00671 for( i = m_filters.begin(); i != m_filters.end(); ++i ) 00672 { 00673 if( i != m_filters.begin() ) 00674 { 00675 oss << ","; 00676 } 00677 oss << (*i).str(); 00678 } 00679 oss << "}]"; 00680 return oss.str(); 00681 } 00682 00683 template<bool Simplify> inline std::ostream& operator<<( std::ostream& out, const TPredicate<Simplify>& p ) 00684 { return out << p.str(); } 00685 00688 typedef TPredicate<false> BasicPredicate; 00689 00692 typedef TPredicate<true> SimplifyingPredicate; 00693 00696 class Message : public siena::message 00697 { 00698 public: 00701 class Value 00702 { 00703 public: 00704 Value(bool b) : type(siena::bool_id), b_value(b) { } 00705 Value(double d) : type(siena::double_id), d_value(d) { } 00706 Value(int i) : type(siena::int_id), i_value(i) { } 00707 Value(std::string s) : type(siena::string_id), s_value(s) { } 00708 00709 Value( const Value& v ) 00710 { 00711 type = v.type; 00712 switch( v.type ) 00713 { 00714 case siena::bool_id: b_value = v.b_value; break; 00715 case siena::double_id: d_value = v.d_value; break; 00716 case siena::int_id: i_value = v.i_value; break; 00717 default: s_value = v.s_value; 00718 } 00719 } 00720 00721 const Value& operator= ( const Value& v ) 00722 { 00723 type = v.type; 00724 switch( v.type ) 00725 { 00726 case siena::bool_id: b_value = v.b_value; break; 00727 case siena::double_id: d_value = v.d_value; break; 00728 case siena::int_id: i_value = v.i_value; break; 00729 default: s_value = v.s_value; 00730 } 00731 return *this; 00732 } 00733 00734 size_t bytesize() const; 00735 00736 std::string str() const; 00737 00738 siena::type_id type; 00739 union 00740 { 00741 bool b_value; 00742 double d_value; 00743 int i_value; 00744 }; 00745 std::string s_value; 00746 }; 00747 00751 class Iterator : public siena::message::iterator 00752 { 00753 std::map<std::string,Value>::const_iterator m_itr; 00754 std::map<std::string,Value>::const_iterator m_end; 00755 public: 00756 Iterator( std::map<std::string,Value>::const_iterator itr, 00757 std::map<std::string,Value>::const_iterator end ) 00758 : m_itr( itr ), m_end( end ) {} 00759 00760 ~Iterator() {} 00761 00762 siena::bool_t bool_value() const 00763 { 00764 if( (*m_itr).second.type != siena::bool_id ) { return false; } 00765 return (*m_itr).second.b_value; 00766 } 00767 00768 siena::double_t double_value() const 00769 { 00770 if( (*m_itr).second.type != siena::double_id ) { return 0.0; } 00771 return (*m_itr).second.d_value; 00772 } 00773 00774 siena::int_t int_value() const 00775 { 00776 if( (*m_itr).second.type != siena::int_id ) { return 0; } 00777 return (*m_itr).second.i_value; 00778 } 00779 00780 siena::string_t string_value() const 00781 { 00782 return siena::string_t( (*m_itr).second.s_value.c_str(), 00783 (*m_itr).second.s_value.length() ); 00784 } 00785 00786 siena::type_id type() const 00787 { return (*m_itr).second.type; } 00788 00789 siena::string_t name() const 00790 { return siena::string_t( (*m_itr).first.c_str(), (*m_itr).first.length() ); } 00791 00792 bool next() 00793 { 00794 if( m_itr == m_end ) 00795 { 00796 return false; 00797 } 00798 return ++m_itr != m_end; 00799 } 00800 }; 00801 00804 Message() {} 00805 00808 Message( const Message& m ) : m_attrMap( m.m_attrMap ) {} 00809 00810 ~Message() {} 00811 00814 const Message& operator= ( const Message& m ) 00815 { m_attrMap = m.m_attrMap; return (*this); } 00816 00820 void add( const std::string& name, bool val ) 00821 { 00822 m_attrMap.insert(make_pair(name, Value(val))); 00823 } 00824 00828 void add( const std::string& name, double val ) 00829 { 00830 m_attrMap.insert(make_pair(name, Value(val))); 00831 } 00832 00836 void add( const std::string& name, int val ) 00837 { 00838 m_attrMap.insert(make_pair(name, Value(val))); 00839 } 00840 00844 void add( const std::string& name, const std::string& val ) 00845 { 00846 m_attrMap.insert(make_pair(name, Value(val))); 00847 } 00848 00852 bool contains( const siena::string_t& name ) const 00853 { return m_attrMap.find( std::string( name.begin, name.length() ) ) != m_attrMap.end(); } 00854 00858 siena::message::iterator* first() const 00859 { 00860 if( m_attrMap.size() == 0 ) { return NULL; } 00861 return new Message::Iterator( m_attrMap.begin(), m_attrMap.end() ); 00862 } 00863 00869 siena::attribute* find( const siena::string_t& name ) const 00870 { 00871 std::map<std::string,Value>::const_iterator itr = m_attrMap.find( std::string( name.begin, name.length() ) ); 00872 if( itr != m_attrMap.end() ) 00873 { 00874 return new Message::Iterator( itr, m_attrMap.end() ); 00875 } 00876 else 00877 { 00878 return NULL; 00879 } 00880 } 00881 00884 const std::map<std::string,Value>& getAttributes() const 00885 { return m_attrMap; } 00886 00889 size_t bytesize() const; 00890 00893 int size() const 00894 { return m_attrMap.size(); } 00895 00900 std::string str() const; 00901 private: 00902 std::map<std::string,Value> m_attrMap; 00903 }; 00904 00905 inline std::ostream& operator<< ( std::ostream& out, const Message& m ) 00906 { return out << m.str(); } 00907 00908 #endif // SIMP_TYPES_H
Copyright © 2001-2004 University of Colorado.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License". This documentation is authored and maintained by Matthew J. Rutherford |