Topic: Proposal for generalization of void *


Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/03/03
Raw View
Christopher Eltschka wrote:
>
> Walter W. Karas wrote:

> [... description of inert<> ...]
>
> I don't think this would be a good idea. A better idea would be to
> write compilers which automatically reuse template instantiations
> with equal properties.

Right

> The only problem I see is that the standard AFAIK mandates different
> addresses for different functions, and different template instantiations
> _are_ different functions, even if their code is bitwise identical.

assert (sizeof (int) == sizeof (long));

template <class T>
T   prod(T lhs, T rhs>
{
    return lhs * rhs;
}

int x;
long y;

prod (3, x) + prod (4L, y);

assert (&prod<int> != &prod<long>); // no ! type mismatch

The linker just as to see that:
- both prod<int> and prod<long> have the same code
- they have different types, so one can't compare
  their addresses

The linker should learn C++ anyway.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Christopher M. Gurnee" <gurnec@nospam.yahoo.com>
Date: 1998/03/03
Raw View
Christopher Eltschka wrote in message
<34FAEBF8.4638B5B0@physik.tu-muenchen.de>...
<snip>
>I don't think this would be a good idea. A better idea would be to
>write compilers which automatically reuse template instantiations
>with equal properties.
>The only problem I see is that the standard AFAIK mandates different
>addresses for different functions, and different template
instantiations
>_are_ different functions, even if their code is bitwise identical.
>Therefore I'd like to relax this to the rule that the addresses of
>two functions generated from the same template may be equal.
>I doubt there are many programs which would break with this change.


I can't find anything in the standard that requires unique functions
have unique addresses.  Although each object must have a unique
address (during its storage duration), functions are not objects.
Even if this restriction did exist, functions could still share code
despite having different addresses.  Consider the following compiled
output:

function1: jmp function4
function2: jmp function4
function3: nop
function4: nop
function5:
  Instructions for all functions here.

Each function has a unique address, but they all share the same code.
In addition, any call to function1-4 not via pointer could go directly
to function5.

<snip>
>This idea looks better to me, although I'd call it just
>packed<T>. I wouldn't like the vptr's to be removed from them,
>however. I think the packed<T> types should be usable just
>as the type T itself, except that using it may be somewhat slow
>(because all data must be extracted = copied to correctly aligned
>memory). This would also allow to resolve the vector<bool>
>problem: Instead of vector<bool>, vector<packed<bool> > would
>be specialized to a bit-vector.

For staters, vector<bool> *is* a packed bit vector (via partial
specialization), so there is no vector<bool> problem.  Your right in
that vptr's shouldn't be removed (IMHO), otherwise how could the
dynamic type be determined?

I don't particularly like the idea of packed<>, but I can't quite put
my finger on why not.  It seems pretty harmless (as long as on
implementations with alignment faults, packed<T> has the same object
representation as T).




[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/03/04
Raw View
Christopher M. Gurnee wrote:
>
> Christopher Eltschka wrote in message
> <34FAEBF8.4638B5B0@physik.tu-muenchen.de>...

[...]

> I can't find anything in the standard that requires unique functions
> have unique addresses.  Although each object must have a unique
> address (during its storage duration), functions are not objects.

Well, I'm glad if I'm wrong here. Hopefully the template optimizing
compilers come soon...

[...]

> <snip>
> >This idea looks better to me, although I'd call it just
> >packed<T>. I wouldn't like the vptr's to be removed from them,
> >however. I think the packed<T> types should be usable just
> >as the type T itself, except that using it may be somewhat slow
> >(because all data must be extracted = copied to correctly aligned
> >memory). This would also allow to resolve the vector<bool>
> >problem: Instead of vector<bool>, vector<packed<bool> > would
> >be specialized to a bit-vector.
>
> For staters, vector<bool> *is* a packed bit vector (via partial
> specialization), so there is no vector<bool> problem.  Your right in
> that vptr's shouldn't be removed (IMHO), otherwise how could the
> dynamic type be determined?

Well, the fact that vector<bool> *is* a packed bit vector is
the problem (or, more exactly, the fact that many people would prefer
to have a non-packed vector<bool> and a separate bit-vector).
OTOH, if we have a packed<bool>, it would be a good idea to
specialize vector<packed<bool> > (note that even a packed<bool>
still needs one char; also note that - only looking at type X -

  struct X { packed<bool> b1, b2; };

would be different from

  struct X_unp { bool b1,b2; };
  typedef packed<X_unp> X;

(I guess it would be reasonable to make the second the same as

  struct X_unp { packed<bool> b1, b2; };
  typedef packed<X_unp> X;

- again only for type X; type X_unp differs, of course).

>
> I don't particularly like the idea of packed<>, but I can't quite put
> my finger on why not.  It seems pretty harmless (as long as on
> implementations with alignment faults, packed<T> has the same object
> representation as T).
>

Need not. Instead, it can use memcpy (or other specific tricks,
like loading two values into registers, and do some bit shifting
+ bitwise logic on them) to put the values into correctly aligned
memory (or into registers) and back.
Of course this would slow it down very much, but actually using
such types for anything but storing/retrieving would be seldom
anyway, and would be known to be slow.

Note that the idea of packing is not really new; Pascal had packed
types very soon (I don't know if they were there initially, but
Turbo Pascal 3.0 explicitly allowed the packed keyword, although
it had no effect there. I think, TP2.0 had the keyword, as well).

Also, AFAIK gcc has a non-standard extension, __attribute__((packed)),
which allows packing (I don't know if only up to byte level, or
even beyond that; I think, it's just byte level).
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Walter W. Karas" <wkaras@ibm.net>
Date: 1998/03/01
Raw View
In C and C++, the "inert" pointer type void * can be used to
create collection data structures that can collect any
pointer type.  I propose an extension to C++ to create
corresponding "inert" types for all types in C++.

C++ already has "pseudo function templates"
(static_cast<X>(), for example).  I propose the "pseudo
class template" inert<X>.  For every type X, there is a
corresponding type inert<X>. inert<> has the following
properties for any type X:

o  static_cast<X>(inert<X>) is valid.
   static_cast<inert<X> >(X) is valid as well.  Furthermore,
   static_cast<X>(static_cast<inert<X> >(x)) does not change
   the value of x.

o  If X(const X &) exists, inert<X>(const inert<X> &) exists.
   Otherwise, if X(X &) exists, inert<X>(inert<X> &) exists.
   X(x) and
   static_cast<X>(inert<X>(static_cast<inert<X> >(x))) must
   produce the same result for all valid x.  Therefore, for
   each value of X, there is a single corresponding value of
   inert<X> given by static_cast<inert<X> >().

o  For each = and == operator valid for two operands of
   type X, there must be a corresponding operator valid for
   two operands of type inert<X>.  If static_cast<inert<X> >
   is applied to two X operands, the corresponding operator
   is applied to the two operands, then static_cast<X> is
   applied to the two operands, the resulting pair will be
   the same as if the X operator were applied to the
   original operand pair.  Furthermore, in the case of
   corresponding == operators, the operator result must be
   the same in the given scenario.

o  If X(void) exists, then inert<X>(void) exists.  If
   inert<X>(void) is substituted for any invocation of
   X(void) the result must be the value of inert<X> that
   corresponds to the value that would have resulted from
   calling X(void).

The simplest implementation for all this is to have inert<X>
simply be X.  Minimally, inert<X> should be the same type
for all types X that are built-in or pointer types and of a
particular size.  For example, on a typical 32-byte
architecture inert<long>, inert<unsigned long> and inert<T
*> (T being any type) should all be the same type. The next
step up would be for all types that assign, copy or compare
byte-by-byte and are of a particular size (perhaps with
padding to some word size) to map to the same inert type.
(If inert<X> has an == operator, static_cast<inert<X> >
would have to zero out "pad" bytes in X.)

So, what is the point of all this?  Consider the following
definitions for a stack container:

template<typename X> class Stack_
  {
  // ...
  public:
    void push(X);
    X pop(void);
  };

template<typename X> class Stack
  : public Stack_<inert<X> >
  {
  public:
    void push(X x)
      { Stack_::push(static_cast<inert<X> >(x)); }
    X pop(void)
      { return(static_cast<X>(Stack_::pop())); }
  };

The use of inert<> reduces the number of instantiations of
Stack_<>.  The wrapper template Stack<> would, with inlining,
generate little or no code.

The existence of inert<> would eliminate the need for partial
template instantiation for pointer types.  I find this feature
to be very unintuitive and difficult to describe formally.
inert<> is also difficult to describe formally, but I would
argue that it is very intuitive.

It might be useful to have a second pseudo template
packed_inert<>.  packed_inert<X> would store instances of
X with all "pad" bytes and vptrs "squeezed out".
packed_inert<> would otherwise work the same as inert<>.
inert-based collection (e.g. Stack) could have a packed
equivalent (e.g. PackedStack) to be used when memory is
dear.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/03/03
Raw View
Walter W. Karas wrote:
>
> In C and C++, the "inert" pointer type void * can be used to
> create collection data structures that can collect any
> pointer type.  I propose an extension to C++ to create
> corresponding "inert" types for all types in C++.
>
> C++ already has "pseudo function templates"
> (static_cast<X>(), for example).  I propose the "pseudo
> class template" inert<X>.  For every type X, there is a
> corresponding type inert<X>. inert<> has the following
> properties for any type X:
>

[... description of inert<> ...]

I don't think this would be a good idea. A better idea would be to
write compilers which automatically reuse template instantiations
with equal properties.
The only problem I see is that the standard AFAIK mandates different
addresses for different functions, and different template instantiations
_are_ different functions, even if their code is bitwise identical.
Therefore I'd like to relax this to the rule that the addresses of
two functions generated from the same template may be equal.
I doubt there are many programs which would break with this change.

> It might be useful to have a second pseudo template
> packed_inert<>.  packed_inert<X> would store instances of
> X with all "pad" bytes and vptrs "squeezed out".
> packed_inert<> would otherwise work the same as inert<>.
> inert-based collection (e.g. Stack) could have a packed
> equivalent (e.g. PackedStack) to be used when memory is
> dear.

This idea looks better to me, although I'd call it just
packed<T>. I wouldn't like the vptr's to be removed from them,
however. I think the packed<T> types should be usable just
as the type T itself, except that using it may be somewhat slow
(because all data must be extracted = copied to correctly aligned
memory). This would also allow to resolve the vector<bool>
problem: Instead of vector<bool>, vector<packed<bool> > would
be specialized to a bit-vector.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]