Any unusual C++ implementations?

  • Thread starter Tomás Ó hÉilidhe
  • Start date
T

Tomás Ó hÉilidhe

I've been writing mostly C code for the last year or so (rather than
C++), and in writing C code I always make it fully portable, allowing for
9-Bit bytes, allowing for padding within integer types, allowing for null
pointers whose bit representation isn't all zeroes, allowing for either
of the three number systems, allowing for character sets other than ASCII
(e.g. 'A' isn't necessarily == 65).

The current project I'm working on is evolving quite a bit though...
and I think I'm being pushed to the edge to switch to C++. First thing I
could do with is namespaces, but also as soon as I get the go-ahead to
use classes I'll be restructuring the code altogether.

Anyway, I'd like to ask if C++ has as wide a variety of
implementations as does C? I mean you'll find a C implementation that has
9-Bit bytes, or 64-Bit bytes, or one that has padding in its integer
types. But what about C++? Is there variety?

The reason I ask is that if there isn't much variety in C++, then I
might switch to making my code less flexible. For instance I might assume
that an unsigned long has no padding and then go on to use it to
manipulate sizeof(unsigned long) bytes at a time.

The program I'm currently writing is mostly comprised of algorithms
that can be coded fully-portably in C, but now that I've decided to make
an interface for it (including a GUI), it's getting a bit more
complicated. I'd switch to C++ in a heartbeat but I want to maintain as
great portability as I can (and of course I'll lose a good chunk of
portability if I move to C++).

Would it be out of the question do you think to leave the algorithmic
code as C, and then write the interface code as C++... ? That way I could
still make commandline programs out of the algorithms.

One thing I won't be doing ever though is assuming 8-Bit bytes or
assuming a 32 or 64-Bit system, because in ten years we could be using
systems with 16-Bit bytes.
 
I

Ian Collins

:

[Are you using an different character set than you declare in your headers?]
Anyway, I'd like to ask if C++ has as wide a variety of
implementations as does C? I mean you'll find a C implementation that
has 9-Bit bytes, or 64-Bit bytes, or one that has padding in its integer
types. But what about C++? Is there variety?
The above have little, if anything to do with the language or compiler.
They are features of the machine, not the language.

So your question should be are there C++ compilers for machines with
these characteristics? Which is probably beyond the scope of this group.

A better question is do you intend your code to be portable to such a
machine? Only you can answer that.
The reason I ask is that if there isn't much variety in C++, then I
might switch to making my code less flexible. For instance I might
assume that an unsigned long has no padding and then go on to use it to
manipulate sizeof(unsigned long) bytes at a time.
A fair assumption, which you can always test for if you wish.
The program I'm currently writing is mostly comprised of algorithms
that can be coded fully-portably in C, but now that I've decided to make
an interface for it (including a GUI), it's getting a bit more
complicated. I'd switch to C++ in a heartbeat but I want to maintain as
great portability as I can (and of course I'll lose a good chunk of
portability if I move to C++).
The addition of a GUI would restrict your possible targets more than the
use of C++.
Would it be out of the question do you think to leave the algorithmic
code as C, and then write the interface code as C++... ? That way I
could still make commandline programs out of the algorithms.
Which ever works best for you, if the routines works as C and you can't
improve the efficiency or clarity of the code by changing to C++, leave
it be. Do remember that if you change to C++, you will have to provide
extern "C" wrappers if you wish to call the routines from C (or code
built with different C++ compilers).
One thing I won't be doing ever though is assuming 8-Bit bytes or
assuming a 32 or 64-Bit system, because in ten years we could be using
systems with 16-Bit bytes.
Many DSP programmers have been for years!
 
J

Juha Nieminen

Tom�������������������������������� said:
For instance I might
assume that an unsigned long has no padding and then go on to use it to
manipulate sizeof(unsigned long) bytes at a time.

That sounds like hacker optimization to me, which is in many cases
useless. Exactly how would you "manipulate sizeof(unsigned long) bytes
at a time"? Care to give an example?
 
T

Tomás Ó hÉilidhe

Ian Collins said:
"Tom����������������������ï
¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½ï¿½" wrote:

[Are you using an different character set than you declare in your
headers?]


Someone tried to help me out with this before but I didn't get far.
My headers say UTF-8, but I'm not quite sure which character set I'm
using. I've been jumping from newsreader to newsreader lately. Last one I
used was "Pan" under Linux, but that was crap so now I'm using "XNews"
under Windows, which I think is great so far. I can't find any option
under XNews however to set the character set. I don't suppose anyone has
any idea which character set I'm using. . ? Because I'll change my header
to specify it if I can't actually get my newsreader to post in UTF-8.

The above have little, if anything to do with the language or
compiler.
They are features of the machine, not the language.


I realise that.

So your question should be are there C++ compilers for machines with
these characteristics? Which is probably beyond the scope of this
group.


I think you're being a bit too restrictive. I'm not asking for the
definition of "WIN_CLASS_REG_INFO_EX" under Win32.

Actually, if you *really* want to be restrictive, you should tell
people to stop posting code, because any discussion about actual
programming should rightfully go in the comp.programming.* hierarchy, and
the comp.lang.* hierarchy should be reserved for talk about the language
itself. (I had this issue when trying to put forward comp.lang.c++.cross-
platform).

A better question is do you intend your code to be portable to such a
machine? Only you can answer that.


I'd like my code to run on every machine on the planet that has a
keyboard and a monitor.

A fair assumption, which you can always test for if you wish.


It would take more work to write two implementations, and more work
still to write the code to check whether implementation A can be used.

The addition of a GUI would restrict your possible targets more than
the use of C++.


I realise that. I'll keep the heart of the program separate from the
interface, such that I can also compile it to a console application and
have it run on anything with a screen and a keyboard.

Which ever works best for you, if the routines works as C and you
can't improve the efficiency or clarity of the code by changing to
C++, leave it be.


I'm just wondering if it would be a bit extreme, or tedious, to
maintain a project which has both C and C++ in it?

Many DSP programmers have been for years!


Ah yes, because a 9-Bit-byte system probably wouldn't so efficient at
sending octets down an ethernet cable. Still though it's not impossible.
With unsigned char's and bitwise operators, the world is your oyster.

Actually it just occurred to me what question I should have asked in the
first place:

Is there a C++ compiler for every machine that has a keyboard and a
monitor? If not, then what kind of proportion of machines are we talking?
Will I get a phonecall from my friend in Antartica telling me he can't
get a C++ compiler for his desktop computer?
 
I

Ian Collins

Tom�������������������������������� said:
I think you're being a bit too restrictive. I'm not asking for the
definition of "WIN_CLASS_REG_INFO_EX" under Win32.
Not at all, the question wasn't about the C++ language, it was about
platforms and tools.
I'd like my code to run on every machine on the planet that has a
keyboard and a monitor.
Then you probably better of sticking to C90. If you want code to run on
some very high percentage of platforms, standard C++ is almost as well
supported as standard C (gcc).
It would take more work to write two implementations, and more work
still to write the code to check whether implementation A can be used.
You have to ask yourself if the effort required to run on some obscure
is worth it. As I said before, only you can answer that. In my
experience, the only time the size of a type matters is for code that is
inherently non-portable, so such issues seldom arise for "standard" C or
C++ code.
I realise that. I'll keep the heart of the program separate from the
interface, such that I can also compile it to a console application and
have it run on anything with a screen and a keyboard.
That separation will allow you stick to standard code, where these
issues don't matter.
I'm just wondering if it would be a bit extreme, or tedious, to
maintain a project which has both C and C++ in it?
Shouldn't be.
 
P

Pascal Bourguignon

Tomás Ó hÉilidhe said:
I'd like my code to run on every machine on the planet that has a
keyboard and a monitor.

This is quite restrictive, most such machines are quite "standard".
You'd have better luck if you let your code run on other machines too,
where you could have more strange processors like DSP or other PIC.
It's true that most of them have a C compiler if a compiler at all,
but it wouldn't be impossible to imagine a C++ compiler there too.

I'm just wondering if it would be a bit extreme, or tedious, to
maintain a project which has both C and C++ in it?

There's mostly no pain it it.
Just use some 'extern "C"{ ... }'.

Of course, you have to be careful with the memory management (you
don't have smart pointers in C, new is not the same as malloc, etc),
and exception handling (no throw/catch/destructor in C, so you don't
have the same opportunities of cleaning up).

Ah yes, because a 9-Bit-byte system probably wouldn't so efficient at
sending octets down an ethernet cable. Still though it's not impossible.
With unsigned char's and bitwise operators, the world is your oyster.

Actually, it wouldn't be any harder or slower to send ethernet packets
from 9-bit/byte buffers, assuming the hardware would skip the ninth bit.

Actually it just occurred to me what question I should have asked in the
first place:

Is there a C++ compiler for every machine that has a keyboard and a
monitor?

Of course not, far from it.

If not, then what kind of proportion of machines are we talking?

Hard to tell. In number of instances or in number of classes?

In number of classes, the hundred of millions of PC count as only one,
and I wouldn't bet that 32-bit machines are the majority (there was
much more architectural variation before 32-bit machines became
common).

In number of instances of course anything that's not 32-bit intel is
insignificant. Even Apple uses Intel nowadays.

Will I get a phonecall from my friend in Antartica telling me he can't
get a C++ compiler for his desktop computer?

Not unless he planed to melt all the ice of Antartica by bringing his
old Univac 1 there. (Univac 1 has a keyboard and monitor (or at least
tty), has 72-bit bytes (in which you can easily pack eight 9-bit
characters) and consumes 125 KW).
 
T

Tomás Ó hÉilidhe

Juha Nieminen said:
That sounds like hacker optimization to me, which is in many cases
useless. Exactly how would you "manipulate sizeof(unsigned long) bytes
at a time"? Care to give an example?


I'd love to... but... I can't help feeling I'd be responding to an
accusation rather than simply conversing.

Have you ever seen an optimised version of memcpy? A fully-portable
implementation might be something like:

void *memcpy(void *const pvdest,void const *const pvsrc,size_t len)
{
char unsigned *dest = static_cast<char unsigned*>(pvdest);
char unsigned const *src = static_cast<char unsigned const*>(pvsrc);

for ( ; len; --len) *dest++ = *src++;

return pvdest;
}


, whereas an optimised one for a particular platform might be:


void *VoidAddition(void *const in,size_t const x)
{
return reinterpret_cast<char*>(in) + x;
}

void *memcpy(void *const pvdest,void const *const pvsrc,size_t len)
{
size_t const quantity_ints = len / sizeof(int);

len %= sizeof(int);

unsigned *pidest = static_cast<unsigned*>(pvdest);
unsigned const *pisrc = static_cast<unsigned const*>(pvsrc);

for (size_t i = quantity_ints; i; --i) *pidest++ = *pisrc++;

size_t const offset = quantity_ints*sizeof(int);

char unsigned *dest = static_cast<char unsigned*>(VoidAddition
(pvdest,offset));
char unsigned const *src = static_cast<char unsigned const*>
(VoidAddition(pvdest,offset));

for ( ; len; --len) *dest++ = *src++;

return pvdest;
}
 
J

James Kanze

I've been writing mostly C code for the last year or so (rather than
C++), and in writing C code I always make it fully portable, allowing for
9-Bit bytes, allowing for padding within integer types, allowing for null
pointers whose bit representation isn't all zeroes, allowing for either
of the three number systems, allowing for character sets other than ASCII
(e.g. 'A' isn't necessarily == 65).
The current project I'm working on is evolving quite a bit though...
and I think I'm being pushed to the edge to switch to C++. First thing I
could do with is namespaces, but also as soon as I get the go-ahead to
use classes I'll be restructuring the code altogether.
Anyway, I'd like to ask if C++ has as wide a variety of
implementations as does C? I mean you'll find a C implementation that has
9-Bit bytes, or 64-Bit bytes, or one that has padding in its integer
types. But what about C++? Is there variety?

Probably. You might check with Comeau; I think that if there is
a C compiler available for the platform, they will manage to
provide C++.

The real question is whether there is still that much variety
left in C. Although the standard allows it, as far as I know,
the last hardware which had padding in an int went out of
production some years ago; the same thing is true for most other
exotics. The only exception I'm aware of is the Unisys
mainframes, which use 36 bit 1's complement integers. And I
would be very surprised if there wasn't a C++ compiler for this
machine. Most of the machines for which there is only C, and
not C++, are very, very small embedded processors, which are all
pretty much 8 bits, 2's complement (when they support signed
arithmetic at all), and IEEE float when they have any floating
point. Similarly, encodings derived from ASCII are universal
outside the mainframe world. (Note, however, that at least some
mainframe compilers present and ASCII world inside C/C++,
translating on the fly whenever the file is opened in text
mode.)
The reason I ask is that if there isn't much variety in C++, then I
might switch to making my code less flexible. For instance I might assume
that an unsigned long has no padding and then go on to use it to
manipulate sizeof(unsigned long) bytes at a time.
The program I'm currently writing is mostly comprised of algorithms
that can be coded fully-portably in C, but now that I've decided to make
an interface for it (including a GUI), it's getting a bit more
complicated. I'd switch to C++ in a heartbeat but I want to maintain as
great portability as I can (and of course I'll lose a good chunk of
portability if I move to C++).

If you support a GUI, you'll loose a lot more portability, a lot
quicker, than just by moving to C++.
Would it be out of the question do you think to leave the algorithmic
code as C, and then write the interface code as C++... ? That way I could
still make commandline programs out of the algorithms.

If the algorithmic code works, why change it?
One thing I won't be doing ever though is assuming 8-Bit bytes or
assuming a 32 or 64-Bit system, because in ten years we could be using
systems with 16-Bit bytes.

There are definitely systems available today with 32 bit bytes.
With C++ compilers. But I don't think that any of them support
a hosted environment.

James Kanze (GABI Software) mailto:[email protected]
Conseils en informatique orient�e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S�mard, 78210 St.-Cyr-l'�cole, France, +33 (0)1 30 23 00 34
 
J

James Kanze

[...]
Of course not, far from it.

Of course, you then have to define exactly what he means by "has
a keyboard and a monitor". Back in the old days, a lot of
embedded processors supported a serial interface, so that you
could connect a terminal for debugging. On the other hand, even
in C, you had to access the IO ports yourself, with some
implementation specific extensions to the compiler.
(Inport/outport, or some such---writing to the "monitor" meant
polling the serial controller until it was ready for output,
then writing your byte.)

I doubt that there are many machines which support a fully
hosted implementation of C, and don't have a C++ compiler as
well.
Hard to tell. In number of instances or in number of classes?
In number of classes, the hundred of millions of PC count as only one,
and I wouldn't bet that 32-bit machines are the majority (there was
much more architectural variation before 32-bit machines became
common).
In number of instances of course anything that's not 32-bit intel is
insignificant. Even Apple uses Intel nowadays.

In number of instances, I suspect that ARM surpasses even Intel.
And I wouldn't be surprised that some small 8 bit embedded
processor surpasses both, by a significant margin. (Of course,
when I was working in the field, the most widespread of such
processors was also Intel. But not x86.)
Not unless he planed to melt all the ice of Antartica by bringing his
old Univac 1 there. (Univac 1 has a keyboard and monitor (or at least
tty), has 72-bit bytes (in which you can easily pack eight 9-bit
characters) and consumes 125 KW).

The modern Unisys mainframes are still 36 bit 1's complement.
(But again, we come back to the question of what he means by
"has a keyboard and monitor". I rather doubt that you can
connect a terminal directly to the Unisys mainframe. You
connect through a special front-end processor---which at Unisys
uses either an Intel or an AMD processors, I forget which.)
 
J

James Kanze

I'd love to... but... I can't help feeling I'd be responding to an
accusation rather than simply conversing.
Have you ever seen an optimised version of memcpy?

Not only seen, written.
A fully-portable
implementation might be something like:
void *memcpy(void *const pvdest,void const *const pvsrc,size_t len)
{
char unsigned *dest = static_cast<char unsigned*>(pvdest);
char unsigned const *src = static_cast<char unsigned const*>(pvsrc);
for ( ; len; --len) *dest++ = *src++;
return pvdest;
}
, whereas an optimised one for a particular platform might be:
void *VoidAddition(void *const in,size_t const x)
{
return reinterpret_cast<char*>(in) + x;
}
void *memcpy(void *const pvdest,void const *const pvsrc,size_t len)
{
size_t const quantity_ints = len / sizeof(int);

len %= sizeof(int);

unsigned *pidest = static_cast<unsigned*>(pvdest);
unsigned const *pisrc = static_cast<unsigned const*>(pvsrc);

for (size_t i = quantity_ints; i; --i) *pidest++ = *pisrc++;

size_t const offset = quantity_ints*sizeof(int);

char unsigned *dest = static_cast<char unsigned*>(VoidAddition
(pvdest,offset));
char unsigned const *src = static_cast<char unsigned const*>
(VoidAddition(pvdest,offset));

for ( ; len; --len) *dest++ = *src++;

return pvdest;
}

That sort of implementation might have been used 20 years ago
(although you'd also have to add logic handling alignment). The
usual solution I've seen, however, is something like:

extern void* memcpy( void*, void const*, size_t ) ;
#define memcpy( d, s, l ) __buildin_memcpy( d, s, l )

with the library version using the straightforward
implementation. A lot of older processors had special
instructions which could be used to great advantage in memcpy.
Alternatively, inline assembler was used in the implementation
(or memcpy was written completely in assembler anyway---which
was what I did).

On modern machines, the straightforward implementation is likely
to be just as fast as anything more complicated, because of the
way pipelining and the various caching work at the hardware
level: the limiting factor will be memory bandwidth, and the
memory interface pipelines will ensure that all writes and reads
are cache line width (e.g.64 bytes).
 
Y

Yannick Tremblay

I'd like my code to run on every machine on the planet that has a
keyboard and a monitor.

Why?

What's the purpose of your code?

What's your market? What's your intended target/audience ?

From a business point of view, your statement most likely makes no
sense because the effort required to support this very rare and very
non-standard platform is unlikely to be worth the rewards.

From a learning experience point of view, your statement is also
misguided because you are not learning to make proper choices that are
applicable in real life situation but instead, you are learning to
waste a pointless amount of effort attempting to solve some
pointlessly irrelevant problem.

From an achievable point of view, your statement makes no sense because
there are machines with a keyboard and a monitor that do not have a C
compiler so you have already lost.

Think about it this way, for example in the GUI and desktop computer
world, if company A write a new application targetting only Win32
while company B tries to write the same new application targetting
Win32, all versions of Linux imaginable, Solaris, BSD, Ultrix, VAX,
BeOS, NextOS, Amiga, Atari, Commodore Vic20 and whatever else you
might think of. Assuming that both companies have the same amount of
resources at the start, by the time Company B has finishes their
idealistic dream product supporting all platforms, company A will have
long released their Win32 v1.0, fixed most bugs in it, got user
feedback and income, hired more programmers to make the improved v2.0,
got more income, hired more programmers to target Linux and Apple
because they are worth it, selected other worthwhile platforms and took
them and released the improved v3.0. When company B turns up on the
market with their all-platforms v1.0, 99% of the potential market will
say: well, that's cool that you support all these platforms but sorry,
the features you are offering us where in company A v1.0 ages ago. We
have now moved to the improved v3.0. Your product is outdated and
doesn't fullfil our current needs.

Note that I am not saying that you must never worry about 9 bits
bytes, only that you must only worry about 9 bits bytes when you must
worry about 9 bits bytes.

Yan
 
T

Tomás Ó hÉilidhe



Much the same reason I'd prefer to be able to eat 7 kinds of food than 6,
it just gives me more options. I hear bears can eat pretty much
anything... I'd say that's handy.

What's the purpose of your code?


That's presently a secret. Suffice to say it's an algorithm whose
inteface can be either commandline or GUI.

What's your market? What's your intended target/audience ?


I don't have a market, because I don't intend on selling anything to make
money. My intended audience is whoever shows an interest.

From a business point of view, your statement most likely makes no
sense because the effort required to support this very rare and very
non-standard platform is unlikely to be worth the rewards.


Thankfully I program out of hobby, not business.

From a learning experience point of view, your statement is also
misguided because you are not learning to make proper choices that are
applicable in real life situation but instead, you are learning to
waste a pointless amount of effort attempting to solve some
pointlessly irrelevant problem.


If a man dedicates his life to climbing all the tallest mountains in the
world, then is that pointless? Well *I'm* not that interested in mountain
climbing, so to me it might seem a bit pointless. Arduous, I'd even say.
But then again I can't speak for our mountain-climbing friend.

Have you considered that maybe I'm making my program ridiculously
portable because I enjoy to write ridiculously portable programs?

From an achievable point of view, your statement makes no sense because
there are machines with a keyboard and a monitor that do not have a C
compiler so you have already lost.


Machines that have a keyboard and monitor... you mean actual computers...
on a desk... with a chair in front... that you sit in front of... and
press keys on the keyboard... and watch what happens on the screen.
There's actually one of these machines out there that doesn't have a C
compiler? Can you name one please? I'm not saying one doesn't exist, but
I can say with a certain amount of certainty that any such machine
represents less than a tenth of a percentage of "machines that have a
keyboard and monitor on a desk with a chair in front that you sit in
front of and press keys on the keyboard and watch what happens on the
screen".

Think about it this way, for example in the GUI and desktop computer
world, if company A write a new application targetting only Win32
while company B tries to write the same new application targetting
Win32, all versions of Linux imaginable, Solaris, BSD, Ultrix, VAX,
BeOS, NextOS, Amiga, Atari, Commodore Vic20 and whatever else you
might think of. Assuming that both companies have the same amount of
resources at the start, by the time Company B has finishes their
idealistic dream product supporting all platforms, company A will have
long released their Win32 v1.0,


Have you compared cross-plaform GUI libraries to the Win32 GUI API? The
Win32 GUI API is disgusting, as is all of their API. Even though a cross-
platfrom GUI library would have to sit on top of the Win32 API, you can
still be sure it'll have a more attractive interface.

fixed most bugs in it, got user
feedback and income, hired more programmers to make the improved v2.0,
got more income, hired more programmers to target Linux and Apple
because they are worth it, selected other worthwhile platforms and took
them and released the improved v3.0.


Well I haven't got much experience with bug-testing, mostly because I
test my functions individually, so I'm not qualified to speak on this.

When company B turns up on the
market with their all-platforms v1.0, 99% of the potential market will
say: well, that's cool that you support all these platforms but sorry,
the features you are offering us where in company A v1.0 ages ago. We
have now moved to the improved v3.0. Your product is outdated and
doesn't fullfil our current needs.


Again, Company B isn't a person in their bedrom room with a laptop on a
desk, programming because they'd rather write a program for an hour or
two than watch television. They might go watch television afterward
though, mind you. Or perhaps they'll give a friend a call and see if the
friend wants to go get ice-cream in the local shopping centre, or go see
a film. Then again actually I want go get back into running real soon but
it's just so damn cold out.

Note that I am not saying that you must never worry about 9 bits
bytes, only that you must only worry about 9 bits bytes when you must
worry about 9 bits bytes.


Thanks for the advice, I'll surely take it on board if I ever sell my
soul and decide to change the way I program for money.
 
T

Tomás Ó hÉilidhe

James Kanze said:
On modern machines, the straightforward implementation is likely
to be just as fast as anything more complicated, because of the
way pipelining and the various caching work at the hardware
level: the limiting factor will be memory bandwidth, and the
memory interface pipelines will ensure that all writes and reads
are cache line width (e.g.64 bytes).


A more suitable set of functions would be:

memcpy_hmmmmm_about_10_bytes_maybe(void*,void const*,size_t);
memcpy_hmmmmm_about_30_bytes_maybe(void*,void const*,size_t);
memcpy_hmmmmm_about_100_bytes_maybe(void*,void const*,size_t);
memcpy_large(void*,void const*,size_t);

I'm sure sensible use of these would yield better performance :-D
 
J

James Kanze

A more suitable set of functions would be:
memcpy_hmmmmm_about_10_bytes_maybe(void*,void const*,size_t);
memcpy_hmmmmm_about_30_bytes_maybe(void*,void const*,size_t);
memcpy_hmmmmm_about_100_bytes_maybe(void*,void const*,size_t);
memcpy_large(void*,void const*,size_t);
I'm sure sensible use of these would yield better performance :-D

Which is roughly what the compiler does when it encounters
__builtin_memcpy. If the size is a constant, or if the
addresses can be determined to be correctly aligned, it can
generate a lot better code than you could do in a general
algorithm.
 

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

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,058
Latest member
QQXCharlot

Latest Threads

Top