Dear list,
Still experimenting on an interpreter implementation in C++
I now have a few questions regarding the instruction structure.
A program is a sequence of instructions that can either be
opcodes or immediate (inline) data types (for my toy: int,
double or ptr). Tagging is not required because the data
type can awalys be deduced by the previous opcode (e.g.
after load_d opcode, I expect a double, after a load_i
opcode comes an int value). Hence I use a union for the
instruction.
But first the opcode. At first, I thought about using
a variant over opcodes as struct, to distach on them with a
visitor. However, current variant (i.e boost:variant) impose
an very large overhead [0] :
for example :
struct load_i {}; struct load_d {}; struct add {}; struct sub{};
-> sizeof(boost::variant<load_i, load_d, add, sub>) == 8 on
my computer, because it stores an int index and an aligned
union of the variant members.
But I'd only need (as in a compressed pair) something along :
struct opcodes : private load_i, load_d, add, sub{
char id;
};
I'd think that it shouldn't be too difficult to devise such
a generic compressed variant (boost::mpl ftw ! :) ) But
is there already such an implementation available ?
But back to the instruction union : as I have small opcodes
(1 byte) and larger data types, I can either have large
instructions (as large as the largest data type) or split
the data into bytes.[*]
Unfortunately, the code that should be the most simple
(the plain union) requires the most boilerplate code
because I do not use a templated generic union and must spell
out each typed access. So my question wrt this implementation
is this: does such a generic union (as std::tuple<> for struct)
exist ? I 'd think it should be straitghforward ot make one :
template <typename... Types> union generic_union;
template<> union generic_union<> {};
template<typename First,typename ... Rest>
union generic_union<First,Rest...>{
First first;
generic_union<Rest...> rest;
};
but I'd sutck on the accessor :I'm *very* new to the variadic
templates and can't resolve the ambiguities raised by my first
crack at it :
template<typename T> struct is_not_in_the_union{};
template<typename T> T& get(generic_union<>& gu)
{ return is_not_in_the_union<T>();}
template<typename T, typename First, typename... Rest >
T& get(generic_union<First,Rest...>& gu){return get<T>(gu.rest);}
template<typename First, typename... Rest>
First& get(generic_union<First, Rest...>& gu) {return gu.first;}
error: call of overloaded 'get(generic_union<int, double>&)' is
ambiguous
note: candidates are: T& get(generic_union<First, Rest ...>&)
[with T = int, First = int, Rest = {double}]
note: First& get(generic_union<First, Rest ...>&)
[with First = int, Rest = {double}]
It make no sens to me that the second is not more specific and
selected as such by the compiler :(
Can someone help me there ?
I look forward to your insights,
Best Regards,
Bernard
[0]
template<bool compact=true>
union instr {
typedef opcode<true> opcode_type;
template<typename T>
union as_bytes {
as_bytes():data(){}
T data;
char bytes[sizeof(T)];
};
instr(opcode_type op= opcode_type::invalid):op(op){}
instr(char byte):byte(byte){}
template<typename T, typename Out>
static Out to_opcodes( T d, Out o)
{ as_bytes<T> b; b.data= d;
return std::copy_n(b.bytes, sizeof(T), o); }
template<typename T, typename In> static T read_data(In& i){
as_bytes<T> b;
std::transform(i, i+sizeof(T), b.bytes, [] (instr i) {return
i.byte;});
std::advance(i, sizeof(T));
return b.data;
}
char byte;
opcode_type op;
};
template<>
union instr<false> {
typedef opcode<false> opcode_type;
instr(opcode_type op= opcode_type::invalid):op(op){}
instr(double d):double_(d){}
instr(int i):int_(i){}
instr(object* o):object_(o){}
template<typename T, typename Out>
static Out to_opcodes( T d, Out o);
template<typename T, typename In> static T read_data(In& i);
opcode_type op;
double double_;
int int_;
object* object_;
};
template<> template<typename Out>
Out instr<false>::to_opcodes(double d, Out o)
{ instr<false> i; i.double_=d; *o=i; return ++o; }
template<> template<typename Out>
Out instr<false>::to_opcodes(int i, Out o)
{ instr<false> i; i.int_=i; *o=i; return ++o; }
template<> template<typename Out> Out
instr<false>::to_opcodes(object* obj, Out o)
{ instr<false> i; i.object_=obj; *o= i; return ++o; }
template<> template<typename In>
double instr<false>::read_data(In& i)
{ return (*(i++)).double_; }
template<> template<typename In>
int instr<false>::read_data(In& i) { return (*(i++)).int_; }
template<> template<typename In>
object* instr<false>::read_data(In& i)
{ return (*(i++)).object_; }
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
bernard
|
12/20/2010 6:19:32 AM |
|
On Dec 20, 6:19 am, bernard <un.compte.pour.tes...@gmail.com> wrote:
[snip]
> But first the opcode. At first, I thought about using
> a variant over opcodes as struct, to distach on them with a
> visitor. However, current variant (i.e boost:variant) impose
> an very large overhead [0] :
> for example :
> struct load_i {}; struct load_d {}; struct add {}; struct sub{};
> -> sizeof(boost::variant<load_i, load_d, add, sub>) == 8 on
> my computer, because it stores an int index and an aligned
> union of the variant members.
>
> But I'd only need (as in a compressed pair) something along :
> struct opcodes : private load_i, load_d, add, sub{
> char id;
>
> };
>
[snip]
The one_of_maybe template:
http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_storage/pack/container_one_of_maybe.hpp
allows specification of the type of the index(for example, char
instead of int) as well as places the index after the value, which
may
save space as explained in some other post to the boost spirit devel
ml
(I can't remember where, but I think it was in same thread mentioned
previously in this thread).
HTH.
-regards,
Larry
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Larry
|
12/20/2010 4:28:23 PM
|
|
On Dec 20, 1:19 pm, bernard <un.compte.pour.tes...@gmail.com> wrote:
> I'd think that it shouldn't be too difficult to devise such
> a generic compressed variant (boost::mpl ftw ! :) )
Indeed, it would just have to use
boost::int_max_value_t<number_of_types>::least instead of int.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Mathias
|
12/20/2010 4:30:16 PM
|
|
On Dec 20, 4:28 pm, Larry Evans <cppljev...@gmail.com> wrote:
> On Dec 20, 6:19 am, bernard <un.compte.pour.tes...@gmail.com> wrote:
> [snip]
>
>> But first the opcode. At first, I thought about using
>> a variant over opcodes as struct, to distach on them with a
>> visitor. However, current variant (i.e boost:variant) impose
>> an very large overhead [0] :
>> for example :
>> struct load_i {}; struct load_d {}; struct add {}; struct sub{};
>> -> sizeof(boost::variant<load_i, load_d, add, sub>) == 8 on
>> my computer, because it stores an int index and an aligned
>> union of the variant members.
>
>> But I'd only need (as in a compressed pair) something along :
>> struct opcodes : private load_i, load_d, add, sub{
>> char id;
>
>> };
>
> [snip]
> The one_of_maybe template:
>
> http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/compo...
>
> allows specification of the type of the index(for example, char
> instead of int) as well as places the index after the value, which
> may
> save space as explained in some other post to the boost spirit devel
> ml
> (I can't remember where, but I think it was in same thread mentioned
> previously in this thread).
>
Output of the test driver:
http://svn.boost.org/svn/boost/sandbox/variadic_templates/libs/composite_storage/sandbox/pack/empty_base.cpp
contains:
sizeof(empties_one_of)=1
showing that the one_of_maybe template size allocates 0 space for
any type, T, such that boost::is_empty<T>::value is true.
The actual is_empty call is done here:
http://svn.boost.org/svn/boost/sandbox/variadic_templates/boost/composite_storage/layout/layout_of.hpp
in case your interested. This may seem unorthodox and maybe even
undefined behaviour, but I'm not sure. However, it seems that if
the compiler can do the empty-base-class optimization, then why
wouldn't it be legal to just not allocation save for it in the
char buf[] used in one_of_maybe (or even boost::variant?
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
Larry
|
12/21/2010 3:32:33 PM
|
|
On Dec 20, 11:30 pm, Mathias Gaunard <loufo...@gmail.com> wrote:
> On Dec 20, 1:19 pm, bernard <un.compte.pour.tes...@gmail.com> wrote:
>
>> I'd think that it shouldn't be too difficult to devise such
>> a generic compressed variant (boost::mpl ftw ! :) )
>
> Indeed, it would just have to use
> boost::int_max_value_t<number_of_types>::least instead of int.
>
In fact, as Larry correctly pointed out[0], the save space will
probably be lost with alignment issues if special care is not
taken to avoid storing data after (in memory layout) the
(byte sized) index.
However, even this would not be enough : I mentioned
"compressed variant" for my "enum as variant" in reference to the
"compressed pair" trick where inheriting from an empty member
instead of storing it avoids wasting one byte on an empty member
variable. I'd need the same in order to have sizeof()==1.
However, I fear that the point is moot because to my great
disappointment, switching on the opcode results in *much*
slower code[1] than indirect goto to stored labels, so
I don't think I'll hide the switch under a visitor,
in order to reuse the same framework for the standard
conformant (switch based) dispatch and the optimized
g++ specific (with stored labels) dispatch.
Best Regards,
Bernard
[0] @Larry Evans : Thanks for the link!
There seems to be a wealth of goodies in that repo.
I can't wait for it to be ready for prime time ! :)
[1] at least in my microbenchmark http://goo.gl/Eqeob
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
0
|
|
|
|
Reply
|
bernard
|
12/21/2010 3:32:47 PM
|
|
|
4 Replies
105 Views
(page loaded in 0.087 seconds)
|