Implementing a tag pointer class

A

alan

Hello world,

I'm trying to implement a (hopefully portable!) tagged pointer class.
Basically, I have my own allocator which will ensure alignment at 8-
byte boundaries (where "byte" is "size of a char"), and allocates
objects of type Generic. My tagged pointer class will support either
Generic* (tag = 0b000) or small integers (tag=0b001) for now (in the
future maybe add unicode chars, and/or Cons* etc.).

A rough sketch of what I intend to do:

class Generic;

class Object {
//public for now, will private this and make the
//external functions friends later
public:
union types {
void* ptr;
int num;
};
types dat;

Object(void* x) {
// in case sizeof(void*) != sizeof(int)
if(sizeof(int) > sizeof(void*)) {
dat.num = 0;
}
dat.ptr = x;
}
Object(int x) {
if(sizeof(void*) > sizeof(int)) {
dat.ptr = 0;
}
dat.num = x;
}

public:
static inline Object smallint(int x) {
x = (x << 3) + 0x1;
return Object(x);
}
static inline Object obj(Generic* x) {
if(x & 0x7) throw AlignmentError();
char* tmp = ((char*)(void*) x) + 0x0;
return Object((void*) tmp);
}
};

static inline char tag(Object x) {
if(sizeof(void*) > sizeof(int)) {
return (char)(((long) x.dat.ptr) & 0x7);
} else {
return (char)(x.dat.num & 0x7);
}
}

static inline bool is_smallint(Object x) {
return tag(x) == 0x1;
}
static inline bool is_obj(Object x) {
return tag(x) == 0x0;
}

static inline int as_smallint(Object x) {
if(!is_smallint(x)) throw TypeError();
return x.dat.num >> 3;
}

static inline Generic* as_obj(Object x) {
if(!is_obj(x)) throw TypeError();
char* tmp = ((char*) x.dat.ptr) - 0x0;
return (Generic*)(void*)tmp;
}

I've tested a version of the above code in a 32-bit x86 GNU/Linux
system with gcc, but I wonder if it's portable, say to big-endian
machines. Also, if optimizations are turned on (-O), it seems to
generate code which approximately looks like what I would expect for
explicit tagged pointers.

I would prefer to use a class-based solution for cleanliness, but I'm
concerned about using unions of potentially differently-sized objects,
especially if the code ends up in a big-endian system with a different
size for pointers and int.

I could also try to dig out the class/type/etc. I saw once which is
supposed to be an integral type that is the same size as the smallest
integer that can fit a void*.

Any pointers and suggestions, as well as analyses on how well this
might perform on various systems/compilers are welcome.

Sincerely,
AmkG
 
A

anon

Victor said:
alan said:
I'm trying to implement a (hopefully portable!) tagged pointer class.
[..]
static inline Object obj(Generic* x) {
if(x & 0x7) throw AlignmentError();

Yeah, he might want to cast x to an int
How does this compile? AFAIUI the binary operator & is not defined for
pointer types...


What's the point of adding 0?

To add: what's point in doing (char*)(void*) ?
 
A

alan

alan said:
I'm trying to implement a (hopefully portable!) tagged pointer class.
[..]
    static inline Object obj(Generic* x) {
        if(x & 0x7) throw AlignmentError();

How does this compile?  AFAIUI the binary operator & is not defined for
pointer types...

Sorry, must have forgot to insert the cast at this point.
What's the point of adding 0?

It's a pattern which I intend to copy for, say, types other than
Generic*. Say Cons*. Or Sym*. The 0x0 is the tag. I can probably
replace the 0x0 with something like:

#define GENERIC_TAG 0x0
#define CONS_TAG 0x2

.....

char* tmp = ((char*)(void*) x) + GENERIC_TAG;

.....

char* tmp = ((char*)(void*) x) + CONS_TAG;

....later on.
        return Object((void*) tmp);
    }
};
[..]

V
 
A

alan

alan said:
I'm trying to implement a (hopefully portable!) tagged pointer class.
[..]
    static inline Object obj(Generic* x) {
        if(x & 0x7) throw AlignmentError();

How does this compile?  AFAIUI the binary operator & is not defined for
pointer types...

Yes, I probably want to add a cast there.
What's the point of adding 0?

It's a pattern I want to copy for other types. Say Cons*. Or Sym*.

I could do:

#define GENERIC_TAG 0x0
#define CONS_TAG 0x2

....

char* tmp = ((char*)(void*) x) + GENERIC_TAG;

....

char* tmp = ((char*)(void*) x) + CONS_TAG;
        return Object((void*) tmp);
    }
};
[..]

V
 
A

alan

Victor said:
alan said:
I'm trying to implement a (hopefully portable!) tagged pointer class.
[..]
    static inline Object obj(Generic* x) {
        if(x & 0x7) throw AlignmentError();

Yeah, he might want to cast x to an int
How does this compile?  AFAIUI the binary operator & is not defined for
pointer types...
What's the point of adding 0?

To add: what's point in doing (char*)(void*) ?

Sorry, I wasn't aware of reinterpret_cast at the time.
 

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top