steve lorimer (64) | Aug 9, 2010 at 7:18pm | |||||
Hi I read this on wikipedia:
http://en.wikipedia.org/wiki/Bit_field Is this relevant? Should I be using something instead of a bit field? I'm advocating using a bit field as in the following code snippet. I prefer this over std::bitset because each bit in a bit field has a name, rather than just a bit position (eg: if (mask.bits.symbol) ...)
I suppose I could have the following:
I don't know... which is preferable? Is it worthwhile me going back over my code which uses bit fields and changing them to bitsets? TIA Steve | ||||||
kbw (2361) | Aug 9, 2010 at 8:06pm |
It depends on where it's used. Are they packed into a message header, or is it an application construct? | |
steve lorimer (64) | Aug 16, 2010 at 6:52pm |
Sorry for the delay in response... It's in an application construct. However, why is this relevant? What's the difference? Thanks Steve | |
kbw (2361) | Aug 16, 2010 at 7:22pm |
The difference is if you want to send these properties at high speed across computer networks, then bit fields are the way to go. If it's in the application, it doesn't quite sound like the thing to do. | |
Last edited on Aug 16, 2010 at 7:22pm |
steve lorimer (64) | Aug 16, 2010 at 7:28pm |
but internal to bitsets the storage is just an unsigned long. Sending the lower 16 bits of a bitset will be the same speed as sending a bitfield which is 16 bits wide. | |
kbw (2361) | Aug 16, 2010 at 8:38pm |
I was answering the wrong question! I was looking at your actual fields and got carried away with thoughts of something else ... namely, why aren't these virtual functions in some Instrument hierarchy. Back to your question, I prefer const's rather than bitfields. I thought they were more portable, but after checking the standard, I can't find a basis for that position. | |
steve lorimer (64) | Aug 16, 2010 at 8:56pm |
They are... sort of! The instrument hierarchy is instrument (abstract) and concrete derivations stock, index, future, option etc However, the mask is stored in instrument base class. I think there is room for improvement! | |
jsmith (4898) | Aug 17, 2010 at 4:30am | ||
Hmm, well, believe it or not but boost doesn't have a solution for this, so I cooked one up quickly. It's a bit rough around the edges, but it is a start:
This allows you to name your bits using C++ types rather than constants. The nice thing about this approach over the constant approach is you can't attempt to access a bit that doesn't exist in the bit field, as would be the problem if you had two independent bitfields, each containing different bits, and two independent sets of constants. The above implementation is limited to 16 bits because my mpl vector is limited to 20 types, thus I chose 16. EDIT: NB: Use of the named type concept as a bit name comes from boost::multi_index_container, which allows for a similar thing with indexes (you can number them, or you can name them. But the above implementation only supports names.) EDIT2: The above implementation also solves the bit ordering problem: you control the order of the bits directly, by virtue of the order of the names in the bitfield<> declaration. B0 is the least significant bit. | |||
Last edited on Aug 17, 2010 at 4:33am |
steve lorimer (64) | Aug 17, 2010 at 1:32pm | ||||
Interesting concept, but unfortunately not very useful when you want to get/set a bit which is determined by a variable's value.
will obviously fail because this is an attempt to use a variable where a constant expression is required. Similarly, processing something like this:
isn't currently supported. You'd have to mix your strongly typed access with unsafe untyped access using a received integer value or whatever. | |||||
R0mai (608) | Aug 17, 2010 at 4:32pm | |
You can add other member functions to the class, like : void set(unsigned n) { bits |= ( 1 << n ); } | ||
jsmith (4898) | Aug 17, 2010 at 7:52pm | ||||||
That, as OP said, degrades the value of the class because the class cannot, at compile time, ensure you are setting a valid bit. It has to be a runtime check. I could write
and the associated functions and validate N at compile time. However what OP wants is the ability to determine what bits to set in a particular line of code at runtime, and templates don't give that ability: it has to be compile time. We could bridge the gap a bit with the above member function and this code:
Although that would break the change I was just about to make to the class - that change being that you cannot call set<>, get<>, flip<>, or reset<>and specify a bit whose type is "none_t" since presumably that bit does not exist. That would make the above function useless; you'd end up writing 15 versions:
| |||||||
steve lorimer (64) | Aug 17, 2010 at 8:12pm | |||||||
This is an interesting thread, but original question remains unanswered, which was namely:
The question was sparked when I read the following on wikipedia:
Breaking down the drawbacks listed above:
When would this become an issue? Does the order of bits in a bitfield differ to the order of bits in say, an unsigned integer? if (mask.all & 0xC1) ... // relies on a certain ordering of bits. Is this not safe with a bitfield?
Really? Surely it could be platform dependant? And surely, if you have memory set to align along the word boundary, you're going to have similar memory consumption and access statistics when using bitfields and bitsets?
Which compilers? Does GCC generate poor code? How does the code generated differ to that of using a variable and a mask? eg:
I like bitfields because I have control over the size, whereas with bitsets you're limited to multiples of unsigned longs. However, with no answers to my questions, I'm of the mindset that std::bitset is what I should go for instead. | ||||||||
jsmith (4898) | Aug 17, 2010 at 9:39pm | ||
Bit ordering would become an issue, for example, if you attempted to read a port, then overlay the value read onto a bit field struct such as your bits_t. inst_type *might* get stored in the least significant bit of the allocated short, or, it might get stored in the most significant bit. I would favor std::bitset<> over the C-style bit fields only because C++ provides very little support for bit fields. You do have control over the size with a bitset<>; that is what the N template parameter is. Yes, it just so happens that bitset<> only allocates multiples of 4 bytes (assuming 32 bit), so you get 4 bytes when you only need 17 bits. On the other hand, even with the C-style bitfield you'll end up wasting space (that's where the padding comes in-- the compiler may choose to align the next struct member on a word boundary, thus 11 bits are wasted). Having said all that, I'm a big proponent of writing code that is as close to maintenance free as possible, and to that end, I can understand why "const uint16_t symbol = 0x0001;" et al. is not the greatest of solutions. I prefer code that is harder to get wrong, which is where my bitfield class came in. Because of bitfield's built-in limitation of 16 bits maximum, you'll probably find it to be faster than bitset<>, since most of my calculations can be done at compile time. Incidentally, here's a new version, that provides most of the API methods that bitset<> provides (albeit some slightly modified):
| |||
Last edited on Aug 17, 2010 at 9:41pm |
jsmith (4898) | Aug 17, 2010 at 9:40pm | ||
| |||
jsmith (4898) | Aug 17, 2010 at 9:40pm | ||
Example code:
| |||
jsmith (4898) | Aug 18, 2010 at 2:16am |
EDIT: there is a bug in all of the above constructors except the default one in that each constructor needs a: bits() in the initializer list. | |
steve lorimer (64) | Aug 18, 2010 at 1:45pm | ||||
That's very cool stuff - thanks. However, in the event that I do want to read a port etc, how do I set the values efficiently; ie: without doing something like this:
I suppose I could do something a little more elegant; perhaps like this:
What would be the recommended way to set multiples of bits at the same time? | |||||
steve lorimer (64) | Aug 18, 2010 at 5:43pm | ||
I've done this for setting individual bits... Strongly typed specification of bits = your structs (bit_zero, et al) Each type has an anonymous enum which specifies the bit position it relates to Calculate the bitmask for each type at compile time (using bit_mask struct below), and pass the result of that & mask to set
| |||
steve lorimer (64) | Aug 18, 2010 at 7:59pm | |
jsmith... I implemented your code, and then came across a strange error.
I've traced that if I include my bitset.h file before boost/asio.hpp I don't get this error. If I include boost/asio.hpp first, then I get the above error! I'm v confused... What causes this error? Do I have the choice of using your bitset or boost's asio classes, but not both? | ||
jsmith (4898) | Aug 18, 2010 at 8:34pm | ||||||||||
Add these to the public interface of the class:
And then you don't need the enum inside the strong types; you can just use the above functions. bit_pos() returns the bit position (0 = least significant bit), and mask() returns the bit mask used to isolate the bit. I'm not sure there really is a way to be much more efficient about setting multiple bits at once. If you want to set bits 2, 3, and 4 at once, you do:
which amounts to
because all other computations are done at compile time. The only way to be faster is to write
such that the right-hand side is evaluated at compile time. If you really want it, we could write a whole slew of methods to do this. Eg:
etc, etc, all the way up to 20 template parameters. Then repeat for reset() and flip(). Can you post bitset.h so I know what lines your line numbers map to? One solution may be to put bitfield in a namespace, but the strange thing is that the only symbol I have in the global namespace is bitfield<> itself. Everything else is scoped either within the detail namespace or within bitfield itself. |
There are 3 files: http://www.mediafire.com/file/16fvmf051l07u6h/bitset.h http://www.mediafire.com/file/81b547kgb2b7m4y/bitset_detail.h http://www.mediafire.com/file/7vz6bj02zcn77yb/bitset_test.cpp I'll post the source here also... please forgive the changes to types/names etc - I was banging my head against a wall trying to see if it was name conflicts - although how it could be when in a unique namespace I don't know! bitset_detail:
| |||
steve lorimer (64) | Aug 18, 2010 at 8:55pm | ||
| |||
steve lorimer (64) | Aug 18, 2010 at 8:56pm | ||
| |||
jsmith (4898) | Aug 18, 2010 at 9:28pm | ||||
EDIT: Actually, I can see the use of set() methods that can set multiple bits at once. For example, if the class' "bits" member was a memory-mapped port, then it would be useful to be able to set or clear or alter the state of multiple bits simultaneously. But my above lines are wrong... they need disable_if's. Ugh. Here's a corrected example. First, change the above from functions to enums. Not sure if the compiler will/can elide the function calls, and there is no need for any of them to be functions anyway.
Next, here is the corrected set() declaration:
| |||||
jsmith (4898) | Aug 18, 2010 at 9:34pm | ||
Here is a corrected (and modified) count() function. The old one had a bug. It shifted 8 bits at a time instead of 4.
| |||
jsmith (4898) | Aug 18, 2010 at 9:41pm |
Can you repost the compile errors with the exact source files you posted? Unfortunately my boost version predates asio, so I cannot compile your code :( | |
steve lorimer (64) | Aug 18, 2010 at 9:52pm | ||||||
Using this post: http://www.cplusplus.com/forum/general/27147/page2.html#msg147084
| |||||||
jsmith (4898) | Aug 18, 2010 at 10:20pm |
Can you try renaming my template parameters from B0 etc to something else like BIT0? Looks kinda like boost.asio might have already defined the symbol B0, perhaps as a macro? | |
steve lorimer (64) | Aug 18, 2010 at 10:25pm |
Aaargh - that is exactly it! I'm a dumbass! :( | |
jsmith (4898) | Aug 18, 2010 at 11:12pm |
That's annoying that asio would define those symbols in the global namespace. | |
steve lorimer (64) | Aug 18, 2010 at 11:12pm | ||
I extended the mask struct to allow creation of a mask from multiple bit types:
| |||
steve lorimer (64) | Aug 25, 2010 at 8:13pm | ||
Do you know of a decent way to convert the types into strings, and then be able to get either a list of strings, or a long concatenated string, of the bits which are set and/or not set? eg, something like this:
TIA Steve | |||
Last edited on Aug 25, 2010 at 8:14pm |
jsmith (4898) | Aug 25, 2010 at 11:06pm | ||||
In namespace detail, add:
In class bitfield, add the public member:
Note: I'm just returning typeid( BitName ).name(), which returns the mangled name. You might consider running the name through a demangler first. [On gcc, it mangles it by prepending an integer corresponding to the length of the type, in characters. So for example, the type "bit_one" gets mangled as "7bit_one". I believe there is a function called __cxa_demangle in cxxabi.h that you might be able to use.] | |||||
steve lorimer (64) | Aug 25, 2010 at 11:07pm |
Thanks once again guru! :) | |
steve lorimer (64) | Aug 26, 2010 at 5:03pm | ||||||
jsmith, if I may avail myself upon thee again please! I'm trying to use your bitset in conjunction with a serialisable message. Here is some code which I'm trying to use for creating my messages:
Now in my client code, I create a message as such:
And if I now want to use my message, I can do the following:
under the hood, msg_t<bitset_t>::field<int, field0>::operator=(U& d) should set the correct bit in both bitsets mask and changes. However, even without attempting to instantiate the msg_t template class above (ie: without declaring struct my_msg, compiling fails with the following error: line 20: error: expected primary-expression before '>' token Any line where I attempt to use the bitset members fails. Since bitset is a template parameter, I would have thought the compiler would only try to parse it when the template is instantiated. Is what I'm trying to do possible? Does it make sense? TIA Steve | |||||||
jsmith (4898) | Aug 26, 2010 at 8:44pm | ||
Yes, it is possible and it makes sense. And even better, there's an easy answer. You just have to add the keyword "template" at the right places:
| |||
Last edited on Aug 26, 2010 at 8:46pm |
steve lorimer (64) | Aug 26, 2010 at 8:56pm |
Wah?!!? what on earth does that mean?! I've never seen syntax like that before?! Why does the compiler need template there? Just when I feel I'm getting a grasp on things, the old curve-ball comes along! :) Thanks once again! | |
steve lorimer (64) | Aug 26, 2010 at 9:23pm |
I'm wondering if Loki's GenScatterHierarchy or something like that would make more sense for what I'm trying to do? | |
jsmith (4898) | Aug 27, 2010 at 1:18am |
So I looked up in the current C++ standard (n3092). I could quote the text here, but it probably wouldn't help. Anyway, the section is 14.2 paragraph 4. Basically, the compiler needs it there because the standard says the compiler needs it there. | |
steve lorimer (64) | Aug 27, 2010 at 4:08pm | ||
Thanks again - I read up the relevant section - so it's to tell the compiler not to parse the first angle bracket as less-than, but rather as a template argument list. I have another question relating to this. The below code snippet is slightly different to the previous snippet I posted, but the basic gist is the same. Given a template class field, which has a member bitset mask (whose type is template param bitset_t), and another template param field_t which specifies the bit position in the bitset, how can I use bitset's local structbit_pos<field_t>::pos to find the bit position in the bitset? See code below:
Currently I get an error line 4: error: expected ‘;’ before ‘::’ token |