Pascal-like set class

Discussion in 'C++' started by Rich Herrick, Sep 4, 2004.

  1. Rich Herrick

    Rich Herrick Guest

    The latest version of my "Pascal-like" set class is available here:

    http://www.richherrick.com/software/herrick-1.0.zip

    Those from the old YAHOO BOOST forum might remember it from several months
    back. I have enhanced the code, and "deboostifized" it.

    For those unfamiliar with it, it is a template class that implements set
    classes that are similar to the set type in the Pascal language. Like
    Pascal, any integer (ordinal) type may be used with the set, but I mainly
    wrote it for use with enumerations. Set elements are stored at the bit
    level, so it is every compact. There is even a member template for defining
    set objects as compile-time constants. I wrote it because none of the C++
    containers (i.e., set and bitset) suited my needs.

    A big change from older versions is the addition of a traits template
    parameter for use gaining finer control over the class' behavior for such
    things as bit ordering and element range (which defaults to [0,
    number-of-elements - 1]).

    Examples from documentation:

    declaration:
    enum color_type
    {NON_COLOR = -1, RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET,
    NUM_COLORS};

    typedef herrick::pascal_set<color_type, NUM_COLORS> color_set;

    compile-time constants:
    const color_set additive_primaries =
    color_set::setof<RED, GREEN, BLUE>::value;

    const color_set subtractive_primaries =
    color_set::setof<RED, YELLOW, BLUE>::value;

    I'd be very interested in comments about the code, the interface (I may have
    went overboard on operators!), or my use of templates (I still get hazy on
    when to use "typename" and "template").

    My goal is to have the interface as much as like the Pascal set type as
    feasible, while having the code conform to the lated standard (regardless
    particular compiler conformity).

    The code currenty compilers with:
    GCC 3.4.0 (MinGW)
    Visual C++ Toolkit 2003


    Rich Herrick
     
    Rich Herrick, Sep 4, 2004
    #1
    1. Advertising

  2. Rich Herrick

    David Hilsee Guest

    "Rich Herrick" <> wrote in
    message news:hXq_c.59663$...
    <snip>
    > I'd be very interested in comments about the code, the interface (I may

    have
    > went overboard on operators!), or my use of templates (I still get hazy on
    > when to use "typename" and "template").

    <snip>

    I think you did go overboard on the operators. Most of the operators for
    that class do not stick to their traditional meaning. Some are close calls,
    but the definitions of operator bool, !, <, <=, >, >=, <<, >>, /, and * look
    odd to me.

    --
    David Hilsee
     
    David Hilsee, Sep 5, 2004
    #2
    1. Advertising

  3. Rich Herrick

    Rich Herrick Guest

    "David Hilsee" <> wrote in message
    news:...
    > "Rich Herrick" <> wrote in
    > message news:hXq_c.59663$...
    > <snip>
    > > I'd be very interested in comments about the code, the interface (I may

    > have
    > > went overboard on operators!), or my use of templates (I still get hazy

    on
    > > when to use "typename" and "template").

    > <snip>
    >
    > I think you did go overboard on the operators. Most of the operators for
    > that class do not stick to their traditional meaning. Some are close

    calls,
    > but the definitions of operator bool, !, <, <=, >, >=, <<, >>, /, and *

    look
    > odd to me.
    >
    > --
    > David Hilsee
    >
    >


    Thanks for replying. All the relational ones match how Pascal defines them,
    and are needed to do subset/superset comparisions. The / and * operators
    are also how Pascal defines them for doing symmetric difference and
    intersection, respectively. There really isn't an operator bool, its really
    operator void*, which will allow testing for a non-empty set in an if
    statement without the nasty side-effects you will get with operator bool.
    Though I will admit that operator void* and operator ! aren't really needed,
    as there is a member that will test for an empty set (and you could also
    test for equals to NULL_SET). The ones I knew someone would question are >>
    and <<, as I almost took them out several times. But I just like the way
    they "look" for adding elements to a set. There is a + operator that does
    the same thing, but I think "S + e1 + e2" looks confusing, especially if e1
    and e2 are integers: S + 1 + 2. I think S << 1 << 2 appears more readable
    in code. Besides, the former creates a new set and the later does not, and
    S += 1 + 2 will, of course, not work. Though again there are many other
    ways to add elements to the set such as: S *= set_type(e1, e2), which will
    union S with the new set, the result of which is in S.

    Thanks,

    Rich Herrick
     
    Rich Herrick, Sep 5, 2004
    #3
  4. Rich Herrick

    David Hilsee Guest

    "Rich Herrick" <> wrote in
    message news:zBM_c.60065$...
    <snip>
    > Thanks for replying. All the relational ones match how Pascal defines

    them,
    > and are needed to do subset/superset comparisions. The / and * operators
    > are also how Pascal defines them for doing symmetric difference and
    > intersection, respectively. There really isn't an operator bool, its

    really
    > operator void*, which will allow testing for a non-empty set in an if
    > statement without the nasty side-effects you will get with operator bool.
    > Though I will admit that operator void* and operator ! aren't really

    needed,
    > as there is a member that will test for an empty set (and you could also
    > test for equals to NULL_SET). The ones I knew someone would question are
    >>

    > and <<, as I almost took them out several times. But I just like the way
    > they "look" for adding elements to a set. There is a + operator that does
    > the same thing, but I think "S + e1 + e2" looks confusing, especially if

    e1
    > and e2 are integers: S + 1 + 2. I think S << 1 << 2 appears more readable
    > in code. Besides, the former creates a new set and the later does not,

    and
    > S += 1 + 2 will, of course, not work. Though again there are many other
    > ways to add elements to the set such as: S *= set_type(e1, e2), which will
    > union S with the new set, the result of which is in S.


    I'll buy the other operators, but I think that <<, >>, !, nad operator void*
    are, at the very least, questionable. Also, the == and != for set
    membership seem odd, because I pronounce the code "If element e is equal to
    set s" when it really means "if set s contains element e".

    A few more questions:

    Why does the traits class provide the array element type? Why would anyone
    want to customize the element?

    Why even bother with an array? Why does std::bitset not provide what you
    need? It took me a few minutes to wrap my head around the "traits" code,
    and then I realized that it was basically implementing std::bitset. I think
    that's what it's doing, anyway.

    --
    David Hilsee
     
    David Hilsee, Sep 6, 2004
    #4
  5. Rich Herrick

    Rich Herrick Guest

    "David Hilsee" <> wrote in message
    news:...
    > "Rich Herrick" <> wrote in
    > message news:zBM_c.60065$...
    > <snip>
    > I'll buy the other operators, but I think that <<, >>, !, nad operator

    void*
    > are, at the very least, questionable. Also, the == and != for set
    > membership seem odd, because I pronounce the code "If element e is equal

    to
    > set s" when it really means "if set s contains element e".

    I agree. To be honest, I had forget about the == and != operators, and in
    my code I use the contains() member. I think I will remove them on future
    releases. But I still waffle back and forth on << and >>. I can see where
    they are extraneous, but I tend to like and use them a lot. The ! and void*
    operator I will probably remove also.

    >
    > A few more questions:
    >
    > Why does the traits class provide the array element type? Why would

    anyone
    > want to customize the element?

    Because, the reason I wrote it was because I wanted low-level control of the
    layout and the size. If I have a set with n items and n <= CHAR_BIT, I may
    want to fit them all into am unsigned char instead of an unsigned int. I do
    a lot of embedded software, dealing with drivers and memory-mapped registers
    and such. I'm use to have that kind of control, and tend to write
    interfaces with that in mind. I also deal with resources that are more
    constrained than an app. writer on a PC might. So, I guess the simple
    answer to your question is they wouldn't, except when the array is only one
    element in size, then I may want to use the smallest int type I can.


    >
    > Why even bother with an array? Why does std::bitset not provide what you
    > need? It took me a few minutes to wrap my head around the "traits" code,
    > and then I realized that it was basically implementing std::bitset. I

    think
    > that's what it's doing, anyway.

    Depends on what you are asking. If you are asking why pascal_set instead of
    bitset, then the answer is pascal_set is more typesafe then bitset and I
    want to mimic the Pascal set type as closely as I could, although I suppose
    I could have just wrapped bitset inside pascal_set. If you are asking why I
    didn't just wrap bitset inside my class instead of using an array, it comes
    down to control. I wanted control of the size and control of the bit-order.
    A lot of what I do interfaces with other languages (I write a lot of C, C++
    and Ada--both '83 and '95), and memory-mapped registers. I have to know the
    layout. pascal_set makes it nice when dealing with set of bit flags in a
    memory-mapped register or an Ada bit array. Though its implementation
    specific, Ada compilers tend to use the MSB as bit 0 on a big-endian machine
    and the LSB as bit 0 on a little-endian machine. I wanted to be able to set
    my bit order to match. Plus, I want to see if I could use templates to
    create compile-set constant sets, which I may not be able to do with bitset.
    This is how the setof template evolved.

    My reasons probably aren't good enough for someone looking for a set class
    to choose mine over bitset or even set. But that's OK, I wrote it for me,
    and found it useful and a joy to use and thought to share it with anyone you
    may be interested. I am currently using it recreationally in writing some
    Interactive Fiction.

    And while writing this, I just thought of a big bug in the whole "traits"
    thing I must now fix....

    Regards.

    --
    Rich Herrick
     
    Rich Herrick, Sep 6, 2004
    #5
  6. Rich Herrick

    Rich Herrick Guest

    By the way David, what is your opinion of the constructors provided? Too
    much?

    Thanks

    --
    Rich Herrick
     
    Rich Herrick, Sep 6, 2004
    #6
  7. Rich Herrick

    David Hilsee Guest

    "Rich Herrick" <> wrote in
    message news:WpS_c.9672$...
    <snip>
    > Because, the reason I wrote it was because I wanted low-level control of

    the
    > layout and the size. If I have a set with n items and n <= CHAR_BIT, I

    may
    > want to fit them all into am unsigned char instead of an unsigned int. I

    do
    > a lot of embedded software, dealing with drivers and memory-mapped

    registers
    > and such. I'm use to have that kind of control, and tend to write
    > interfaces with that in mind. I also deal with resources that are more
    > constrained than an app. writer on a PC might. So, I guess the simple
    > answer to your question is they wouldn't, except when the array is only

    one
    > element in size, then I may want to use the smallest int type I can.


    I understand that, but I'm surprised that there would be cases where you
    would want to use an unsigned char, and other cases where you would want to
    use an unsigned int. In the latter case, wouldn't you just use multiple
    unsigned chars? I've never done embedded programming, so I might be
    overlooking something. Is there an alignment issue?

    --
    David Hilsee
     
    David Hilsee, Sep 6, 2004
    #7
  8. Rich Herrick

    David Hilsee Guest

    "Rich Herrick" <> wrote in
    message news:xNS_c.9673$...
    > By the way David, what is your opinion of the constructors provided? Too
    > much?

    <snip>

    I don't see any problem with them. Many might be unnecessary, though,
    thanks to the ones that take arrays. I can see how they look a tad nicer
    than the equivalent code that uses arrays, though.

    --
    David Hilsee
     
    David Hilsee, Sep 6, 2004
    #8
  9. Rich Herrick

    Rich Herrick Guest

    "David Hilsee" <> wrote in message
    news:...

    > I understand that, but I'm surprised that there would be cases where you
    > would want to use an unsigned char, and other cases where you would want

    to
    > use an unsigned int. In the latter case, wouldn't you just use multiple
    > unsigned chars? I've never done embedded programming, so I might be
    > overlooking something. Is there an alignment issue?
    >
    > --
    > David Hilsee
    >

    Well, one reason would be a memory-mapped register accessed across a VME
    bus. If a 16-bit register that is mapped as a D16 access, but you attempt
    to access it as a D32 or 2 D8, you will get a data access exception. Same
    with an 8-bit register. So, if I make the underlining type match (which
    again is implementation specific), I can access it with my class.

    If I had a large set, then sure, I would use int, because the set operations
    are done on a whole int at a time, not bit. So, on a platform where int is
    32 bits, and I had a set with 64 elements, it would do a union in two
    operations, not 64. But, on the other hand, if I may be more concerned with
    size. If, assuming char is 8 bits, and I need my set to fit into 24 bits
    (maybe its in a struct talking to an Ada record, and Ada had a
    representation specification that maps it into 24 bits), I can achieve this
    by setting the unit type to unsigned char. I would be trading efficiency to
    make it fit, but that would probably not be an issue.

    --
    Rich Herrick
     
    Rich Herrick, Sep 6, 2004
    #9
  10. Rich Herrick

    Rich Herrick Guest

    "David Hilsee" <> wrote in message
    news:...
    > "Rich Herrick" <> wrote in
    > message news:xNS_c.9673$...
    > > By the way David, what is your opinion of the constructors provided?

    Too
    > > much?

    > <snip>
    >
    > I don't see any problem with them. Many might be unnecessary, though,
    > thanks to the ones that take arrays. I can see how they look a tad nicer
    > than the equivalent code that uses arrays, though.
    >
    > --
    > David Hilsee
    >
    >

    I wrote the multitude of constructors that take different numbers of
    elements for type-safety (over var. length args.) and efficiently. I was
    wondering if maybe the array ones were too much (especially since there is
    two of them).

    Thanks for your insights.

    --
    Rich Herrick
     
    Rich Herrick, Sep 6, 2004
    #10
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Adam

    Pascal-style "types"

    Adam, Feb 19, 2005, in forum: ASP .Net
    Replies:
    3
    Views:
    359
  2. Ivan Vecerina
    Replies:
    1
    Views:
    1,275
    Jerry Coffin
    Oct 21, 2003
  3. Jeff Schwab

    Translating from C to Pascal

    Jeff Schwab, Dec 31, 2003, in forum: C++
    Replies:
    10
    Views:
    703
    Jeff Schwab
    Jan 1, 2004
  4. Chris Gordon-Smith

    Calling Pascal from C++ and Vice Versa

    Chris Gordon-Smith, Jan 17, 2004, in forum: C++
    Replies:
    4
    Views:
    3,028
    EventHelix.com
    Jan 18, 2004
  5. Patrick Kowalzick
    Replies:
    5
    Views:
    500
    Patrick Kowalzick
    Mar 14, 2006
Loading...

Share This Page