[Home] [Downloads] [Search] [Help/forum]


Register forum user name Search FAQ

Gammon Forum

Notice: Any messages purporting to come from this site telling you that your password has expired, or that you need to "verify" your details, making threats, or asking for money, are spam. We do not email users with any such messages. If you have lost your password you can obtain a new one by using the password reset link.
 Entire forum ➜ Programming ➜ STL ➜ Newer, Better, Cooler Bitmask-Flags

Newer, Better, Cooler Bitmask-Flags

It is now over 60 days since the last post. This thread is closed.     Refresh page


Pages: 1 2  

Posted by David Haley   USA  (3,881 posts)  Bio
Date Fri 28 May 2004 11:58 PM (UTC)
Message
For all those fortunate enough to be using C++, I suggest you check out the bitset class.

http://www.josuttis.com/libbook/cont/bitset1.cpp.html

Basically, you have a class that can be expanded to as many flags as you want. I suspect that the template figures out how many bytes it needs to allocate, and then when you ask it for a given entry it automagically figures out which byte to mask against.

This is a pristine solution to the problem of expandable bitmask flags. I pity the poor souls stuck with C. :-)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Samson   USA  (683 posts)  Bio
Date Reply #1 on Sun 30 May 2004 05:01 AM (UTC)
Message
Nice, very nice. Looks like I'll be seeing about getting this used in my codebase. Was just wondering if you've run across a link with better information. This one doesn't seem to give a complete example of how to use it. Went looking for something better but I'm not really finding much.
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #2 on Sun 30 May 2004 05:19 AM (UTC)
Message
Yes, I'll definitely be using this gem as well. This is what I love about the STL: it has so much stuff done for you already that really lets you worry about more important things, and not pesky little flags and stuff. :-)

The link I gave you is from Josuttis's excellent book. Unfortunately, he only made his examples publicly available. :) The best starting point I would suggest is:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vcstdlib/html/vclrfBitsetbitset.asp
which is the MSDN page for the bitset.

That being said the example seems to cover most of it. Coupled with the MSDN example, I think we can pretty much figure it out. It seems that if you write it to an ostream, it gives the binary representation. I'd imagine that reading from an istream into a bitset produces much the same results.

Here is the index page will all his examples:
http://www.josuttis.com/libbook/idx.html

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Samson   USA  (683 posts)  Bio
Date Reply #3 on Sun 30 May 2004 06:58 AM (UTC)
Message
Cool, checked the MSDN link and it has all the stuff you need to make use of this. Excellent find. I went in and changed one of the small sections of code that used the usual BV00 type definitions. It converted over flawlessly. Not only that, but using the to_ulong() conversion is perfect for saving numerical flag values. The file format doesn't need to change, and using an fread_number to load the value back into the bitset worked perfectly.

I'll expand my use of it to some more isolated areas of the code and see what I get from it. If things work out with that, converting all of the flag types to use this should be easy. I'm so glad I chose to save most of my flag values as text strings now :)
Top

Posted by David Haley   USA  (3,881 posts)  Bio
Date Reply #4 on Sun 30 May 2004 08:24 PM (UTC)
Message
Does to_ulong work even if you have more than 32 entries in your bitset? I haven't played around with this a lot yet so I wouldn't know.

And yes, I too have discovered the wisdom of saving as much as possible as text and not as evil numbers. :)

David Haley aka Ksilyan
Head Programmer,
Legends of the Darkstone

http://david.the-haleys.org
Top

Posted by Samson   USA  (683 posts)  Bio
Date Reply #5 on Mon 31 May 2004 03:30 AM (UTC)
Message
I doubt to_ulong() will do the job for a conversion if you're above BV32. So for stuff in the current "extended" bitvector style, using text to save the fields is probably still best. None of the information I've found so far has provided any examples of saving bitset stuff to files, so I'm winging it in this area as it is.
Top

Posted by Samson   USA  (683 posts)  Bio
Date Reply #6 on Sat 26 Jun 2004 11:54 PM (UTC)

Amended on Sat 26 Jun 2004 11:55 PM (UTC) by Samson

Message

char *bitset_string( unsigned long flag, int flagmax, char *const flagarray[] )
{
   static char buf[MSL];
   int x;

   buf[0] = '\0';
   for( x = 0; x < flagmax; x++ )
	if( IS_SET( flag, 1 << x ) )
	{
	   mudstrlcat( buf, flagarray[x], MSL );
         /* don't catenate a blank if the last char is blank  --Gorog */
         if( buf[0] != '\0' && ' ' != buf[strlen(buf)-1] )
            mudstrlcat( buf, " ", MSL );
	}

   if( ( x = strlen( buf ) ) > 0 )
      buf[--x] = '\0';

   return buf;
}


The above code is what I cooked up to do conversions on the new bitset stuff from the bits that are set to the string which can represent them for saving in files and such. It works great, provided you don't go over what an unsigned long can hold. Trouble is, an unsigned long is insufficient for any of my extended bitvector cases. Further, I've apparently discovered that the to_string() conversion for std::bitset isn't available in g++ 3.3x which is the compiler I'm using.

So this creates a dillema. How do I manage to convert my extended cases into std::bitset and still be able to manipulate them?

As a quick example, if I try to print one of the normal ones to string format, this is the error I get:

channels.c: In function `void do_showchannels(char_data*, char*)':
channels.c:429: error: no matching function for call to `std::bitset<2u>::to_string()'

Should be noted also that this error triggers itself on g++ 3.4.0 as well, so if this is something the GNU C++ compiler is supposed to know about, perhaps I've found a bug that needs to be brought to GNU's attention?
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #7 on Sun 27 Jun 2004 07:59 AM (UTC)

Amended on Sun 27 Jun 2004 08:01 AM (UTC) by Nick Gammon

Message
According to Josuttis book p 468:

Quote:


The function (to_string) is a template function that is parameterized only by return type. According to the language rules, you must write the following:

bitset<50> b;
b.template to_string<char, char_traits<char>,allocator<char> > ()


What this means a bit more plainly is that you cannot just use to_string, you must use the template code. The example program below works under g++ 3.2.2.

#include <bitset>
#include <iostream>

using namespace std;

int main (void)
  {
  bitset<50> mybits;

  mybits.set (1);
  mybits.set (5);
  mybits.set (40);

  cout << "bits = " <<
    mybits.template to_string<char, char_traits<char>,allocator<char> > () <<
    endl;

  }




Output


bits = 00000000010000000000000000000000000000000000100010


Hope this helps.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #8 on Sun 27 Jun 2004 08:06 AM (UTC)
Message
You could make a define to do the dirty work for you, like this:


#include <bitset>
#include <iostream>

using namespace std;

#define bitset_to_string(arg) \
  arg.template to_string<char, char_traits<char>,allocator<char> > ()

int main (void)
  {
  bitset<50> mybits;

  mybits.set (1);
  mybits.set (5);
  mybits.set (40);

  cout << "bits = " << bitset_to_string (mybits) << endl;

  }


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #9 on Sun 27 Jun 2004 08:09 AM (UTC)
Message
Another, simpler, approach is to just use the output stream. This works and gives the same results:


#include <bitset>
#include <iostream>

using namespace std;

int main (void)
  {
  bitset<50> mybits;

  mybits.set (1);
  mybits.set (5);
  mybits.set (40);

  cout << "bits = " << mybits << endl;

  }



- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #10 on Sun 27 Jun 2004 08:13 AM (UTC)

Amended on Sun 27 Jun 2004 11:36 PM (UTC) by Nick Gammon

Message
Another approach again, if you want a string and not to go direct to cout, is to use a MAKE_STRING macro, like this:


#include <bitset>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

// this define lets you create a string on-the-fly
// you can use output modifiers in the string, eg.
// string mystr = MAKE_STRING (
//    "hello " << boolalpha << true << hex << 1234 << octal << 3456 << dec
//    << 123456 << scientific << 123.45 << fixed << 1234.567 " );

#define MAKE_STRING(msg) \
   (((ostringstream&) (ostringstream() << boolalpha << msg)).str())


int main (void)
  {
  bitset<50> mybits;

  mybits.set (1);
  mybits.set (5);
  mybits.set (40);

string s;

  s = MAKE_STRING (mybits);

  cout << "bits = " << s << endl;

  }

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #11 on Sun 27 Jun 2004 08:27 AM (UTC)

Amended on Sun 27 Jun 2004 11:36 PM (UTC) by Nick Gammon

Message
The example below illustrates reading the bitset back in. I certainly wouldn't use a long to handle the bits, that defeats the whole purpose of being able to use more than 32 of them.


#include <bitset>
#include <string>
#include <sstream>
#include <iostream>

using namespace std;

#define MAKE_STRING(msg) \
   (((ostringstream&) (ostringstream() << boolalpha << msg)).str())

int main (void)
  {
  bitset<50> mybits;

  mybits.set (1);
  mybits.set (5);
  mybits.set (40);

string s;

  s = MAKE_STRING (mybits);

  cout << "bits = " << s << endl;

// now read it back in

  bitset<50> newbits;

  istringstream str (s);
  str >> newbits;
  if (str.fail ())
    {
    cout << "Invalid bits" << endl;
    return 1;
    }

  cout << "new  = " << newbits << endl;
  }

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #12 on Sun 27 Jun 2004 10:13 PM (UTC)

Amended on Sun 27 Jun 2004 10:14 PM (UTC) by Nick Gammon

Message
Another approach, rather than using bitset, which limits you to deciding how many bits you want, in advance, is to use a map of bools (or a vector of bools for that matter). Here is one way:


#include <map>
#include <string>
#include <iostream>

using namespace std;

int main (void)
  {
  map <int, bool> flags;

  flags [1] = true;
  flags [5] = true;
  flags [40] = true;

  for (map <int, bool>::const_iterator i = flags.begin ();
       i != flags.end ();
       i++)
    cout << "bit " << i->first << " = " << i->second << endl;
  }



Output

bit 1 = 1
bit 5 = 1
bit 40 = 1


This system lets you use *any* flag numbers (eg. 10000) because the map simply stores the keys it is given.

- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Nick Gammon   Australia  (23,046 posts)  Bio   Forum Administrator
Date Reply #13 on Sun 27 Jun 2004 10:17 PM (UTC)
Message
Once you have got that far, you can use named flags, which make it easier to program in the first place, and easier to read the area files, like this:


#include <map>
#include <string>
#include <iostream>

using namespace std;

int main (void)
  {
  map <string, bool> flags;

  flags ["dark"] = true;
  flags ["inside"] = true;
  flags ["nomob"] = true;

  for (map <string, bool>::const_iterator i = flags.begin ();
       i != flags.end ();
       i++)
    cout << "bit " << i->first << " = " << i->second << endl;
  }



Output

bit dark = 1
bit inside = 1
bit nomob = 1


- Nick Gammon

www.gammon.com.au, www.mushclient.com
Top

Posted by Samson   USA  (683 posts)  Bio
Date Reply #14 on Sun 27 Jun 2004 10:45 PM (UTC)

Amended on Sun 27 Jun 2004 10:47 PM (UTC) by Samson

Message
Well, all very good suggestions. After prodding a few things, I came up with this:


char *bitset_string( std::basic_string< char, std::char_traits<char>, std::allocator<char> > flags, int flagmax, char *const flagarray[] )
{
   static char buf[MSL];
   char newflags[MSL];
   int x;

   mudstrlcpy( newflags, flags.c_str(), MSL );

   invert( newflags, log_buf );
   mudstrlcpy( newflags, log_buf, MSL );

   buf[0] = '\0';
   for( x = 0; x < flagmax; x++ )
	if( newflags[x] == '1' )
	{
	   mudstrlcat( buf, flagarray[x], MSL );
         /* don't catenate a blank if the last char is blank  --Gorog */
         if( buf[0] != '\0' && ' ' != buf[strlen(buf)-1] )
            mudstrlcat( buf, " ", MSL );
	}

   if( ( x = strlen( buf ) ) > 0 )
      buf[--x] = '\0';

   return buf;
}


That's in build.c, right next to ext_flag_string and such. The first argument uses this macro:


#define BITSTRING( arg ) (arg).to_string< char, std::char_traits<char>, std::allocator<char> > ()


So basically now all I have to do is call it like so:

bitset_string( BITSTRING( channel->flags ), CHAN_MAXFLAG, chan_flags )

Yes, it's a bit of a hackish looking mess, but it's getting the job done and has already proven to work on a bitset with 65 members, which is far beyond what a ulong can hold.

The invert function was used because the normal bitset string is backward for this purpose. The lowest bits are at the rightmost portion of the string. The inversion made walking the string trivial at that point.
Top

The dates and times for posts above are shown in Universal Co-ordinated Time (UTC).

To show them in your local time you can join the forum, and then set the 'time correction' field in your profile to the number of hours difference between your location and UTC time.


66,608 views.

This is page 1, subject is 2 pages long: 1 2  [Next page]

It is now over 60 days since the last post. This thread is closed.     Refresh page

Go to topic:           Search the forum


[Go to top] top

Quick links: MUSHclient. MUSHclient help. Forum shortcuts. Posting templates. Lua modules. Lua documentation.

Information and images on this site are licensed under the Creative Commons Attribution 3.0 Australia License unless stated otherwise.

[Home]