|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Want a new Job?
Chapters
Services
Feature Zones
|
IntroductionCompilers MSVC v6.0/v7.0 are not supported. This project requires a compliant compiler. MSVC v7.1 or GCC v3.2.3 will work just fine. I have another handy (I hope) addition to the TTL library. Suppose, we need to define a set of flags that can be passed around. Typically, we would use macros to define the flags and an integer data type to hold them. An example might look like the following code: #define WND_STYLE_CAPTION 0x01 #define WND_STYLE_BORDER 0x02 void set_style( int style ); First of all, using macros for defining constants is not always a very good idea. The reason is that macro names belong to the global namespace. For instance, you cannot do something like: namespace x { #define WND_STYLE_CAPTION 0x01 #define WND_STYLE_BORDER 0x02 }; namespace y { #define WND_STYLE_CAPTION 0x01 #define WND_STYLE_BORDER 0x02 }; main() { int fx = x::WND_STYLE_CAPTION; int fy = y::WND_STYLE_CAPTION; } To resolve the problem, we can use namespace x { enum winstyle { WND_STYLE_CAPTION = 1, WND_STYLE_BORDER = 1<<1 }; }; namespace y { enum winstyle { WND_STYLE_CAPTION = 1, WND_STYLE_BORDER = 1<<1 }; }; main() { int fx = x::WND_STYLE_CAPTION; int fy = y::WND_STYLE_CAPTION; } An even better solution is: namespace x { struct winstyle { enum type { CAPTION = 1, BORDER = 1<<1 }; }; }; namespace y { struct winstyle { enum type { CAPTION = 1, BORDER = 1<<1 }; }; }; main() { int fx = x::winstyle::CAPTION; int fy = y::winstyle::BORDER|y::winstyle::CAPTION; } Now, everything works fine... well, almost. The problem is that we don't have type safety. The following code illustrates the problem: //we cannot just use 'winstyle' as the //parameter type because it is a combination //of winstyle values. void set_style( int style ) main() { int x = 8989; //'x' is just an integer and has nothing to do //with window styles... but the compiler //doesn't know about it an it is compiled just fine. set_style( x ); } There is another problem that is the type of the flags holder. To hold a combination of flags, people usually use std::vector< int > styles; In such a case, on a 32 bit machine, we'll be allocating 3 extra bytes per vector element. So we need to watch as to what the optimal flags holder type should be. Clearly we have two objectives:
ImplementationThe implementation is relatively straightforward. Here are some ideas. The complete implementation can be found in TTL. namespace impl { template< int Bits, int type = Bits <= sizeof(char)*8? 1:(Bits <= sizeof(short)*8?2:(Bits <= sizeof(int)*8?3:4)) > struct bestfit; template< int Bits > struct bestfit<Bits, 1> { typedef unsigned char type; }; template< int Bits > struct bestfit<Bits, 2> { typedef unsigned short type; }; template< int Bits > struct bestfit<Bits, 3> { typedef unsigned int type; }; template< int Bits > struct bestfit<Bits, 4> { typedef unsigned int type; }; }; template< typename T, int Bits = sizeof(int)*8, typename Holder = typename impl::bestfit<Bits>::type > struct flags { typedef flags this_t; typedef T value_type; Holder f_; flags() : f_(0) {} flags( T f1 ) : f_(f1) {} flags( T f1, T f2 ) : f_(f1|f2) {} flags( T f1, T f2, T f3 ) : f_(f1|f2|f3) {} ... this_t& operator |=( const this_t& f ) { f_ |= f.f_; return *this; } this_t& operator &=( const this_t& f ) { f_ &= f.f_; return *this; } this_t operator~() { f_ = ~f_; return *this; } bool operator ==( const this_t& l ) const { return f_ == l.f_; } bool operator !=( const this_t& l ) const { return f_ != l.f_; } bool operator !() { return f_ == 0; } Holder get_holder() const { return f_; } bool test( const this_t& l ) const { return (f_ & l.f_)?true:false; } bool test() const { return f_!=0; } }; template< typename T, int Bits, typename Holder > flags<T, Bits, Holder> operator |(const flags<T, Bits, Holder>& l, const T& r) { flags<T, Bits, Holder> tmp( r ); return l|tmp; } template< typename T, int Bits, typename Holder > flags<T, Bits, Holder> operator |(const flags<T, Bits, Holder>& l, const flags<T, Bits, Holder>& r) { flags<T, Bits, Holder> tmp( l ); tmp|=r; return tmp; } template< typename T, int Bits, typename Holder > flags<T, Bits, Holder> operator &(const flags<T, Bits, Holder>& l, const T& r) { flags<T, Bits, Holder> tmp( r ); return l&tmp; } template< typename T, int Bits, typename Holder > flags<T, Bits, Holder> operator &(const flags<T, Bits, Holder>& l, const flags<T, Bits, Holder>& r) { flags<T, Bits, Holder> tmp( l ); tmp&=r; return tmp; } As you can see, we use the UsageBack to our example: struct winstyle { enum type { CAPTION = 1, BORDER = 1<<1, size = 2 //the last used bit }; }; //use our new class template typedef flags<winstyle, winstyle::size> winstyle_flags; How do old flags compare to the new ones? main()
{
int fy = winstyle::BORDER|winstyle::CAPTION;
}
is equivalent to: main()
{
winstyle_flags fy(winstyle::BORDER, winstyle::CAPTION);
}
In the current implementation, you can initialize The second template parameter in Now, our void set_style( winstyle_flags style );
The usage of main()
{
winstyle_flags fx( winstyle::CAPTION );
winstyle_flags fy( winstyle::BORDER, winstyle::CAPTION);
if( fx == fy )
{
...
}
fx |= y::winstyle::BORDER;
if( fx.test(winstyle::CAPTION) ) //is CAPTION set
{
...
}
winstyle_flags fz = fx & fy;
}
TTL has a function for mapping one set of flags to another set. For instance, if we need to map our //flag_map keeps a map of pairs (my_flag, win32_flag) struct flag_map { //the first parameter is the key typedef std::multimap< winstyle_flags, int > map; //the above could also be //typedef std::vector< std::pair< winstyle_flags, int > > map; flag_map() { if( init_ ) //initialize only once { init_ = false; map_.insert( winstyle::CAPTION, WS_CAPTION ); map_.insert( winstyle::BORDER, WS_BORDER ); } } static bool init_; static map map_; } void set_style( winstyle_flags style ); main() { set_style( winstyle_flags(winstyle::CAPTION,winstyle::BORDER) ) } void set_style( winstyle_flags style ) { flag_map map; //map our flags to Win32 int w32style = ttl::flg::flag_mapper( map.map_.begin(), map.map_.end(), style ); ::CreateWindow( ... w32style ); //use Win32 function with 'style' :) }
If you do need to convert winstyle_flags fx( winstyle::CAPTION );
int f = fx.get_holder();
Using TTLTTL is a completely header based library. There is no need to link to any .lib files. To use TTL:
Enjoy!
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||