By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,543 Members | 2,085 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,543 IT Pros & Developers. It's quick & easy.

Nodes with unlimited children.

P: n/a
Hi All,

I plan on using the following C++ code
to create nodes with unlimited children:

// I would like to declare NodeT like this,
// but it won't compile because Lnk_T is not defined yet.

struct NodeT { Lnk_T Lnk ; };

So I have to declare NodeT like this instead:

struct NodeT {
struct { NodeT * * B, * * E, * * Room ; } Lnk ; };
typedef NodeT * Link ;

typedef Link * Link_P ;

// B is the Beginning of an array of pointers.
// E is the End of an array of pointers that are in use.
// Room the end of an array of all pointers, used or not.

struct Lnk_T { Link_P B, E, Room ; };

Lnk_T Lnk ;

enum { Chunk = 4,
Sz_Ptr = sizeof Link, Sz_Node = sizeof NodeT };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link_P ) realloc( Lnk.B, Room * Sz_Ptr );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Ptr ); }
// Below is an example of is how the above might be used,
// I know that it works.

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

GrowList ( Lnk ); // Lnk is a global, so it's initialized.

Link & P = * Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

{ Link Passed = P, & P = * Passed->Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

// etc.
}

But is there any way to declare NodeT so that
I don't have to use that ( Lnk_T & ) cast ?
Jul 22 '05 #1
Share this Question
Share on Google+
47 Replies


P: n/a
Jeff Relf wrote:
Hi All,

I plan on using the following C++ code
to create nodes with unlimited children:

// I would like to declare NodeT like this,
// but it won't compile because Lnk_T is not defined yet.

struct NodeT { Lnk_T Lnk ; };

So I have to declare NodeT like this instead:

struct NodeT {
struct { NodeT * * B, * * E, * * Room ; } Lnk ; };
typedef NodeT * Link ;

typedef Link * Link_P ;

// B is the Beginning of an array of pointers.
// E is the End of an array of pointers that are in use.
// Room the end of an array of all pointers, used or not.

struct Lnk_T { Link_P B, E, Room ; };

Lnk_T Lnk ;

enum { Chunk = 4,
Sz_Ptr = sizeof Link, Sz_Node = sizeof NodeT };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link_P ) realloc( Lnk.B, Room * Sz_Ptr );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Ptr ); }
// Below is an example of is how the above might be used,
// I know that it works.

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

GrowList ( Lnk ); // Lnk is a global, so it's initialized.

Link & P = * Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

{ Link Passed = P, & P = * Passed->Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

// etc.
}

But is there any way to declare NodeT so that
I don't have to use that ( Lnk_T & ) cast ?


That doesn't sound type safe.

And modern computing demands type safety.

--
incognito @ http://kentpsychedelic.blogspot.com
Jul 22 '05 #2

P: n/a
On 29 Jul 2004 11:06:12 GMT, Jeff Relf wrote:
Hi All,

I plan on using the following C++ code
to create nodes with unlimited children:

// I would like to declare NodeT like this,
// but it won't compile because Lnk_T is not defined yet.

struct NodeT { Lnk_T Lnk ; };

So I have to declare NodeT like this instead:

struct NodeT {
struct { NodeT * * B, * * E, * * Room ; } Lnk ; };
typedef NodeT * Link ;

typedef Link * Link_P ;

// B is the Beginning of an array of pointers.
// E is the End of an array of pointers that are in use.
// Room the end of an array of all pointers, used or not.

struct Lnk_T { Link_P B, E, Room ; };

Lnk_T Lnk ;

enum { Chunk = 4,
Sz_Ptr = sizeof Link, Sz_Node = sizeof NodeT };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link_P ) realloc( Lnk.B, Room * Sz_Ptr );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Ptr ); }
// Below is an example of is how the above might be used,
// I know that it works.

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

GrowList ( Lnk ); // Lnk is a global, so it's initialized.

Link & P = * Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

{ Link Passed = P, & P = * Passed->Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

// etc.
}

But is there any way to declare NodeT so that
I don't have to use that ( Lnk_T & ) cast ?


Good lord, that's the worst code I've ever seen. I hope I don't ever
have to maintain something of yours.

It's considered polite, when incrementing a pointer value, to bracket to
explicity show what you're intending, i.e.
(*p)++ return the value at the pointer, then increment the value
*(p++) return the value at the pointer, then increment the pointer

Maybe I got those backwards. Which is why you really want to be explicit.

--
FreeBSD 4.8-RELEASE i386
11:20AM up 130 days, 3:23, 1 user, load averages: 0.00, 0.01, 0.00
Jul 22 '05 #3

P: n/a
Karl Heinz Buchegger

Re: Nodes with unlimited children,

You wrote,
" Start the whole thing with a forward declaration of NodeT. "

Oh, how so very sweet, thank you much !

By the way,
I just realized that the code that I showed in my original
post was really designed for a NodeT of varying length,
which I don't think I really need.

So this is how it looks now ( and it works ),

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// E is the End of an array of NodeT's that are in use.
// Room the end of an array of all NodeT's, used or not.

struct Lnk_T { Link B, E, Room ; };

struct NodeT { Lnk_T Lnk ; };

Lnk_T Lnk ;

enum { Sz_Node = sizeof NodeT, Chunk_Lnk = 4 };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk_Lnk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node ); }

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

// Lnk is a global, so it's initialized.
// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( ( * Lnk.E ++ ).Lnk );

// etc
}

You wrote,
" BTW: I consider your formatting style horrible. "

Everyone employs whitespace differently,
I even change my own style from time to time.

So I don't see how it's worth commenting on.
Jul 22 '05 #4

P: n/a

"Jeff Relf" <Jeff_Relf_@_NCPlus.NET.Invalid> wrote in message
news:_J*************************@NCPlus.NET...
Hi All,

I plan on using the following C++ code
to create nodes with unlimited children:


<code snipped>

There's a clever way to get this effect with only two Node *'s per Node:

class Node
{
/* put data here */
Node *firstChild;
Node *nextSibling;
};

Then, to get all the children of a node, you just do
for (Node *child = myNode->firstChild; child != 0; child =
child->nextSibling) {
// whatever
}

This works great as long as you don't need constant-time access to the
nth child of a Node.

Joe Gottman


Jul 22 '05 #5

P: n/a
Hi General Protection Fault,

Re: Precedence vs. overused parentheses,
such as: ( * Lnk.E ++ ).Lnk in the following code,

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// E is the End of an array of NodeT's that are in use.
// Room the end of an array of all NodeT's, used or not.

struct Lnk_T { Link B, E, Room ; };

struct NodeT { Lnk_T Lnk ; };

Lnk_T Lnk ;

enum { Sz_Node = sizeof NodeT, Chunk_Lnk = 4 };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk_Lnk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node ); }

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

// Lnk is a global, so it's initialized.
// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( ( * Lnk.E ++ ).Lnk );

// etc
}

If you're asking me,
it's much better to know the precedence of operators
than to overuse parentheses.

For example:
( * Lnk.E ++ ).Lnk is better than ( * ( Lnk.E ++ ) ).Lnk

But it's subjective, so why quibble ?

As for you maintaining my code,
I wouldn't worry about that if I were you.

Here is the order of precedence, highest first:
++ Post-increment, Left to right
-- Post-decrement
( ) Function call
[ ] Array element
-> Pointer to structure member
.. Structure or union member
++ Pre-increment, Right to left
-- Pre-decrement
! Logical NOT
~ Bitwise NOT
- Unary minus
+ Unary plus
& Address
* Indirection
sizeof Size in bytes
new Allocate program memory
delete Deallocate program memory
( type ) Type cast [ for example, ( float ) i ]
..* Pointer to member ( objects ), Left to right
->* Pointer to member ( pointers )
* Multiply, Left to right
/ Divide
% Remainder
+ Add, Left to right
- Subtract
<< Left shift, Left to right
Right shift
< Less than, Left to right
<= Less than or equal to Greater than
= Greater than or equal to

== Equal, Left to right
!= Not equal
& Bitwise AND, Left to right
^ Bitwise exclusive OR, Left to right
| Bitwise OR, Left to right
&& Logical AND, Left to right
|| Logical OR, Left to right
? : Conditional, Right to left
= Assignment, Right to left
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Compound assignment
, Comma, Left to right

Jul 22 '05 #6

P: n/a
Jeff Relf wrote:
Hi General Protection Fault,

Re: Precedence vs. overused parentheses,
such as: ( * Lnk.E ++ ).Lnk in the following code,

struct NodeT ;

What a bunch of boring bullshit.

Here's something more interesting. I was writing a c# service and that
created a file that would then be transferred somewhere else. Originally I
coded some meta-data in the file name, but then because that had specific
size requirements, I had to use something else. How about File Properties
( right click on a text file, and look at the Properties ( third ) tab. It
has stuff like Author, Title, Subject.

I figure those nice m$ people created a cool assembly that would let me
set/get those. Well there is a class with get methods but not set methods.
So, I had to use a COM object that M$ supplies called DFOfile.dll

Yeah, so, when you dig a little beneath the pretty surface of .NET -- it's
all COM.

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// E is the End of an array of NodeT's that are in use.
// Room the end of an array of all NodeT's, used or not.

struct Lnk_T { Link B, E, Room ; };

struct NodeT { Lnk_T Lnk ; };

Lnk_T Lnk ;

enum { Sz_Node = sizeof NodeT, Chunk_Lnk = 4 };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk_Lnk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node ); }

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

// Lnk is a global, so it's initialized.
// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( ( * Lnk.E ++ ).Lnk );

// etc
}

If you're asking me,
it's much better to know the precedence of operators
than to overuse parentheses.

For example:
( * Lnk.E ++ ).Lnk is better than ( * ( Lnk.E ++ ) ).Lnk

But it's subjective, so why quibble ?

As for you maintaining my code,
I wouldn't worry about that if I were you.

Here is the order of precedence, highest first:
++ Post-increment, Left to right
-- Post-decrement
( ) Function call
[ ] Array element
-> Pointer to structure member
. Structure or union member
++ Pre-increment, Right to left
-- Pre-decrement
! Logical NOT
~ Bitwise NOT
- Unary minus
+ Unary plus
& Address
* Indirection
sizeof Size in bytes
new Allocate program memory
delete Deallocate program memory
( type ) Type cast [ for example, ( float ) i ]
.* Pointer to member ( objects ), Left to right
->* Pointer to member ( pointers )
* Multiply, Left to right
/ Divide
% Remainder
+ Add, Left to right
- Subtract
<< Left shift, Left to right
Right shift

< Less than, Left to right
<= Less than or equal to
Greater than
= Greater than or equal to

== Equal, Left to right
!= Not equal
& Bitwise AND, Left to right
^ Bitwise exclusive OR, Left to right
| Bitwise OR, Left to right
&& Logical AND, Left to right
|| Logical OR, Left to right
? : Conditional, Right to left
= Assignment, Right to left
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Compound assignment
, Comma, Left to right


--
http://kentpsychedelic.blogspot.com
Jul 22 '05 #7

P: n/a
Oops, I should've said:

I prefer Lnk.E ++ -> Lnk over ( Lnk.E ++ ) -> Lnk

Jul 22 '05 #8

P: n/a
Hi Joe Gottman,

You showed something similar this:

class Node_Type {
Node * firstChild ;
Node * nextSibling ; };

for ( Node_Type * child = myNode->firstChild ;
child != 0 ;
child = child->nextSibling ) ...
For what I'm doing, I prefer my dynamic array of nodes.

such as: Lnk.E ++ -> Lnk ( defined below ),

That allows me to do things like: Lnk.B [ 4 ]
which directly references the fifth node.

My NodeT is very small and has a fixed size,
if NodeT was large or if it had a dynamic size
I'd use the code that I originally posted in this thread:
news:_J*************************@NCPlus.NET

To loop though all the child nodes I define this:
( Lnk is a global, see below )

#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.E )

Which is then called like this:

LoopChildren _Lnk->Whatever ;

Here's how I declared those variables:

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// E is the End of an array of NodeT's that are in use.
// Room the end of an array of all NodeT's, used or not.

struct Lnk_T { Link B, E, Room ; };

struct NodeT { int Whatever ; Lnk_T Lnk ; };

Lnk_T Lnk ; // This is a global variable, so it's initialized.

enum { Sz_Node = sizeof NodeT, Chunk_Lnk = 4 };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk_Lnk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node ); }

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( Lnk.E ++ -> Lnk );

// etc
}

Jul 22 '05 #9

P: n/a
Hi International All-Star Cast,

Win XP's File Properties is... well... specific to Win XP,
and therefore it can't be part of the main C# framework.

I'm sure that there is
plenty of C# code that only runs on Win XP.

To be sure that your C# code _ Shines _
on dual 64-bit PowerPCs as well as on some arcane cell phone,
you'd better damn well test it on all of those devices.
Jul 22 '05 #10

P: n/a
Jeff Relf wrote:
Hi International All-Star Cast,

Win XP's File Properties is... well... specific to Win XP,
and therefore it can't be part of the main C# framework.

I'm sure that there is
plenty of C# code that only runs on Win XP.

To be sure that your C# code _ Shines _
on dual 64-bit PowerPCs as well as on some arcane cell phone,
you'd better damn well test it on all of those devices.


Sure, sure, but it's a web service...so I could care less.

Yesterday, I wrote an synchronous Delegate ( what you overtrained c++ might
term a callback function ) so that my GUI web service consumer could do
work in the background.

It's very cool.

--
http://kentpsychedelic.blogspot.com
Jul 22 '05 #11

P: n/a
Jeff Relf wrote:

You wrote,
" BTW: I consider your formatting style horrible. "

Everyone employs whitespace differently,
I even change my own style from time to time.

It's not only about whitespace.

Eg.

// B is the Beginning of an array of NodeT's.
// E is the End of an array of NodeT's that are in use.
// Room the end of an array of all NodeT's, used or not.

struct Lnk_T { Link B, E, Room ; };

Why do you need the comment? To describe what B, E and Room
are for. So then why not write it more verbose in the
first place:

struct Lnk_T { Link Beginn, End, Room ; };

Why everything on one line?

struct Lnk_T
{
Link Begin;
Link End;
Link Room;
};

Same for the code. Your code looks like one of the early
C programmers who thought that cramming as much as they can
into a single line is a good idea. It is not! Everybody
programming for years and having to maintain old code knows
this. One of the most important things in a code (besides
beeing correct) is maintainability.

Compare

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk_Lnk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node ); }

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

// Lnk is a global, so it's initialized.
// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( ( * Lnk.E ++ ).Lnk );

// etc
}

To

void GrowList ( Lnk_T & Lnk )
{
if ( Lnk.E + 1 < Lnk.Room )
return;

int Room = Lnk.Room - Lnk.B + Chunk_Lnk;
int E = Lnk.E - Lnk.B ;

Lnk.B = ( Link ) realloc( Lnk.B, Room * Sz_Node );
Lnk.Room = Lnk.B + Room ;
Lnk.E = Lnk.B + E ;

memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Node );
}

BTW what you do with pointers and int in the above is illegal.
I wonder why your compiler didn't barf on it.
__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{

// Lnk is a global, so it's initialized.
// This creates a child for Lnk.
// There is no limit to the number of children.
GrowList ( Lnk );

// This creates a grandchild for Lnk.
GrowList ( ( * Lnk.E ++ ).Lnk );

// etc
}

In your code I didn't see where GrowList end and WinMain starts.
It took me reformatting to notice that I accidently copied not
only one function but two. And I didn't notice until I had the
whole thing in the newreader.
So I don't see how it's worth commenting on.


It is. Because at least in this group (clc++) we are used to
see problem request which can be traced back to simply bad
formatting. Reformatting and reindenting shows the error
quite clearly. So the regulars do this, reply with the
reformatted code and the OP sees his problem on his own.

Your code is the worst case I have seen for a long time.

Just because I notice it right now. You are also posting to
comp.os.linux.advocacy. Is this intended? Your code contains
__stdcall WinMain( ... )
which is clearly not a linux thing.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #12

P: n/a
Karl Heinz Buchegger wrote:


BTW what you do with pointers and int in the above is illegal.
I wonder why your compiler didn't barf on it.


Forget that. It is legal.
My fault.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #13

P: n/a
Hi Karl Heinz Buchegger,

You wrote, << ...in this group ( clc++ )
we are used to seeing problems/requests
which can be traced back to simply bad formatting.
Reformatting and reindenting shows the errors quite clearly.

So the regulars do this,
reply with the reformatted code
and the OP sees his problem on his own. >>

I'm of the opinion that one's choice of whitespace
and the names one chooses for the identifiers
is less important than just going over the code.

i.e. It helps to simply change the whitespace,
no matter how you change it.

For that very reason, I often change my style.

Besides, my original question was answered quickly by you
after you examined the first few lines of my post.
( And for that I thank you )

What style of code is more maintainable ?

I can't answer that question.

Re: struct Lnk_T { Link B, E, Room ; };

You suggested that
I would not need so many comment lines if I wrote it as:

struct Lnk_T
{
Link Begin;
Link End;
Link Room;
};

It's ironic that you would rename those 3 variables,
because after examining this code myself
I've decided to change them to: B, P, and E.

I much prefer the shorter names for often used pointers.

B is what I usually call the beginning of a buffer,
and E what I call the end of a buffer,
and P is what I call my working pointer.

So long as the scope is kept small, it works quite well.

Another change I made was to pre-increment P inside Inc(),
( the function that makes room for it )
so now P always points to the current Node.

Pre-incrementing is always my preference.

Using your preferred whitespace style ( kind of ),
my code now looks like this:

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// P is the Pointer to the NodeT in use.
// E is the End of an array NodeT's.
// Inc() increments P.

struct Lnk_T
{
Link B, P, E ;
};

struct NodeT
{
int Whatever ;
Lnk_T Lnk ;
};

Lnk_T Lnk ; // A global, so it's already initialized.

enum {
Sz_Node = sizeof NodeT
};

NodeT & Inc ( Lnk_T & Ln )
{
if ( Ln.E && ++ Ln.P < Ln.E )
return * Ln.P ;

int E = Ln.E - Ln.B + 4 ;
int P = Ln.P - Ln.B ;

Ln.B = ( Link ) realloc( Ln.B, E * Sz_Node );
Ln.E = Ln.B + E ;
Ln.P = Ln.B + P ;

memset( Ln.P, 0, ( Ln.E - Ln.P ) * Sz_Node );

return * Ln.P ;
}

// The - 1 below is so that I can pre-increment.

#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.P )

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{

// In the line below, the first call to Inc()
// creates one child for Lnk ( Lnk is a global )
// and returns it as a reference to Lnk.P
//
// That child is then is passed in a second call to InC(),
// thus creating a grandchild
// and returning a reference to Lnk.P->Lnk.P.
//
// There is no limit to the number of children per node.
//
// Afterwards Lnk.P->Lnk.P->Whatever
// is valid and is initialized to zero.

printf( "%d", Inc ( Inc ( Lnk ).Lnk )->Whatever );

// This prints all of Lnk's children.

LoopChildren printf( "%d", _Lnk->Whatever );

}
P.S.

I cross-posted to Comp.OS.Linux.Advocacy ( Cola )
because I'm only reading that group, not Comp.Lang.C++.

And yes, as my WinMain() hinted at,
I only program for Win XP.

I'm only in Cola because I have some friends there.
Jul 22 '05 #14

P: n/a
Oops, two errors,

It's printf( "%d", Inc ( Inc ( Lnk ).Lnk ).Whatever );
not printf( "%d", Inc ( Inc ( Lnk ).Lnk )->Whatever );

Because the each call to Inc()
returns it as a reference to * Lnk.P, not Lnk.P
Jul 22 '05 #15

P: n/a
Jeff Relf wrote:

Hi Karl Heinz Buchegger,

You wrote, << ...in this group ( clc++ )
we are used to seeing problems/requests
which can be traced back to simply bad formatting.
Reformatting and reindenting shows the errors quite clearly.

So the regulars do this,
reply with the reformatted code
and the OP sees his problem on his own. >>

I'm of the opinion that one's choice of whitespace
and the names one chooses for the identifiers
is less important than just going over the code.

i.e. It helps to simply change the whitespace,
no matter how you change it.

For that very reason, I often change my style.

Besides, my original question was answered quickly by you
after you examined the first few lines of my post.
Quickly is good.
I had to cut&paste that mess into my editor and start
reindenting and reformatting to even have a chance to
figure out what is wrong and in which way it needs
to be changed

It's ironic that you would rename those 3 variables,
because after examining this code myself
I've decided to change them to: B, P, and E.
Which only proofs that it is possible to write Fortran
code in every language.
(Apologies to Fortran programmers. Although I didn't write
Fortran programs since 15 years any more, I know that
Fortran has evolved in this time.)

I cross-posted to Comp.OS.Linux.Advocacy ( Cola )
because I'm only reading that group, not Comp.Lang.C++.


Good reason :-)
--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #16

P: n/a
"Jeff Relf" <Jeff_Relf_@_NCPlus.NET.Invalid> wrote in message
news:_J*************************@NCPlus.NET...
Re: Precedence vs. overused parentheses,
such as: ( * Lnk.E ++ ).Lnk in the following code,


Um... the parentheses are necessary in this expression. If you were to
write

*Lnk.E++.Lnk

it would mean the same as

*((Lnk.E++).Lnk)
Jul 22 '05 #17

P: n/a
Jeff Relf <Jeff_Relf_@_NCPlus.NET.Invalid> wrote in message

Why is this message crossposted to comp.os.linux.advocacy?
For example:
( * Lnk.E ++ ).Lnk is better than ( * ( Lnk.E ++ ) ).Lnk
Assuming I understand the intent of your code, my preference is

const LnkType& OldLnk = Lnk.E.Lnk;
++Lnk.E; // as opposed to the equivalent ++(Lnk.E)

Here is the order of precedence, highest first:
++ Post-increment, Left to right
-- Post-decrement
( ) Function call
[ ] Array element
-> Pointer to structure member
. Structure or union member
++ Pre-increment, Right to left
-- Pre-decrement
! Logical NOT
~ Bitwise NOT
- Unary minus
+ Unary plus
& Address
* Indirection
sizeof Size in bytes
new Allocate program memory
delete Deallocate program memory
( type ) Type cast [ for example, ( float ) i ]
.* Pointer to member ( objects ), Left to right
->* Pointer to member ( pointers )
* Multiply, Left to right
/ Divide
% Remainder
+ Add, Left to right
- Subtract
<< Left shift, Left to right
Right shift
< Less than, Left to right
<= Less than or equal to
Greater than
= Greater than or equal to

== Equal, Left to right
!= Not equal
& Bitwise AND, Left to right
^ Bitwise exclusive OR, Left to right
| Bitwise OR, Left to right
&& Logical AND, Left to right
|| Logical OR, Left to right
? : Conditional, Right to left
= Assignment, Right to left
*=, /=, %=, +=, -=, <<=, >>=, &=, ^=, |= Compound assignment
, Comma, Left to right


The list is incorrect. The operators are grouped into boxes, and each
box has a higher priority than the one after it, but within each box
the operators have the same priority. For example, your list above
has + before -, which suggests that a-b+c is a-(b+c), but it is really
(a-b)+c. There's usually no difference when a, b, c are integers or
any type with the commutivity property, but if you have overloaded
operators you should see operator- called first, then
operator+. As an aside, consider overflow: a=UNIT_MAX, b=UNIT_MAX,
c=1, and a-b+c should be 1, but a-(b+c) is either an overflow
exception or UINT_MAX. I wonder if there are any examples to prove
that operators are grouped into boxes other than overloaded operators
and overflow/underflow considerations.

So instead of
+ Add, Left to right
- Subtract


I'd write either

+ Add, Left to right; - Subtract

or

Next Group/Box
+ Add, Left to right
- Subtract
Jul 22 '05 #18

P: n/a
In comp.os.linux.advocacy, General Protection Fault
<ge*******@braids.ertw.com>
wrote
on Thu, 29 Jul 2004 16:28:09 GMT
<slrncgi9a7.2st1.ge*******@braids.ertw.com>:
On 29 Jul 2004 11:06:12 GMT, Jeff Relf wrote:
Hi All,

I plan on using the following C++ code
to create nodes with unlimited children:

// I would like to declare NodeT like this,
// but it won't compile because Lnk_T is not defined yet.

struct NodeT { Lnk_T Lnk ; };

So I have to declare NodeT like this instead:

struct NodeT {
struct { NodeT * * B, * * E, * * Room ; } Lnk ; };
typedef NodeT * Link ;

typedef Link * Link_P ;

// B is the Beginning of an array of pointers.
// E is the End of an array of pointers that are in use.
// Room the end of an array of all pointers, used or not.

struct Lnk_T { Link_P B, E, Room ; };

Lnk_T Lnk ;

enum { Chunk = 4,
Sz_Ptr = sizeof Link, Sz_Node = sizeof NodeT };

GrowList ( Lnk_T & Lnk ) {
if ( Lnk.E + 1 < Lnk.Room ) return;
int Room = Lnk.Room - Lnk.B + Chunk, E = Lnk.E - Lnk.B ;
Lnk.B = ( Link_P ) realloc( Lnk.B, Room * Sz_Ptr );
Lnk.Room = Lnk.B + Room ; Lnk.E = Lnk.B + E ;
memset( Lnk.E, 0, ( Lnk.Room - Lnk.E ) * Sz_Ptr ); }
// Below is an example of is how the above might be used,
// I know that it works.

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int ) {

GrowList ( Lnk ); // Lnk is a global, so it's initialized.

Link & P = * Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

{ Link Passed = P, & P = * Passed->Lnk.E ++ ;

P = ( Link ) realloc( P, Sz_Node );

memset ( P, 0, Sz_Node );

GrowList ( ( Lnk_T & ) P->Lnk );

// etc.
}

But is there any way to declare NodeT so that
I don't have to use that ( Lnk_T & ) cast ?
Good lord, that's the worst code I've ever seen. I hope I don't ever
have to maintain something of yours.


ObEgo: What about my code? :-)

I posted a variant of an HTML colorizer some time ago
after JR posted code that was absolutely terrible (longer
than -- and worse than -- this stuff). With STL, it came
out rather clean, but Jeff apparently hasn't learned the
wonders of std::map yet. :-)

I'm not sure the above actually *does* anything, either -- except
maintain a collection of Room objects, and a far simpler method
of doing that (if one does want a doubly-linked list) is to
simply declare

std::list<Room> roomList;

and use the STL manipulators, some of which can be quite sophisticated
(for_each() is one of the simpler algorithms; there's a fair number
of others):

struct RoomManipulator { operator()(Room & r) { ... } } manipo;
void manipf(Room & r);

std::for_each(roomList.begin(), roomList.end(), manipo);

or one can use the simpler

std::for_each(roomList.begin(), roomList.end(), manipf);

if one doesn't need to keep state.

Or one one can do it with an explicit iterator:

for(std::list<Room>::const_iterator i = roomList.begin();
i != roomList.end(); i++)
{
...
}

If one wants a list of Room *pointers* instead (there are some issues
that may require such), the declaration is simply changed to:

std::list<Room *> roomPointerList;

and the code suitably modified -- although ideally it wouldn't
make that much difference.

Or one can declare a templated "smart pointer" class:

std::list<std::auto_ptr<Room> > roomPointerList

Unfortunately std::auto_ptr<> isn't the brightest of resource
managers. I wrote my own long ago, but it's a bit klunky
as it requires friend access in order to properly manage
the usecount (one per object).

If one doesn't like lists, one can use various other
collection forms: std::set and std::hashset if one wants
a sorted collection, and std::vector if one wants to keep
things contiguous in memory (although the block of memory
may in fact move). std::vector might be a good replacement
for some of Jeff's code here. The aforementioned std::map
might be useful if one needs namevalue pairs; std::hashmap
might be slightly faster if one doesn't need the pairs
sorted in any recognizable order.

I'm not sure how efficient STL is (although a lot of the
implementation is inline), but it's one of the more elegant
constructs I've come across. Admittedly, though, some of
the implementation details can get a bit on the grody side.

It's considered polite, when incrementing a pointer value, to bracket to
explicity show what you're intending, i.e.
(*p)++ return the value at the pointer, then increment
the value
*(p++) return the value at the pointer, then increment the pointer

Maybe I got those backwards. Which is why you really want to be explicit.


The C/C++ spec does define the precedence of '*' versus '++' but I for
one can't remember which binds more tightly, and I'm probably not alone.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #19

P: n/a
On Fri, 30 Jul 2004 13:01:16 -0700, The Ghost In The Machine wrote:
Or one can declare a templated "smart pointer" class:

std::list<std::auto_ptr<Room> > roomPointerList


This is undefined behavior. std::auto_ptr cannot be used as a standard
container member because it doesn't have the copy semantics that the
standard containers require.

Ali
Jul 22 '05 #20

P: n/a
In comp.os.linux.advocacy, Ali Cehreli
<ac******@yahoo.com>
wrote
on Fri, 30 Jul 2004 14:35:08 -0700
<pa*********************************@yahoo.com>:
On Fri, 30 Jul 2004 13:01:16 -0700, The Ghost In The Machine wrote:
Or one can declare a templated "smart pointer" class:

std::list<std::auto_ptr<Room> > roomPointerList


This is undefined behavior. std::auto_ptr cannot be used as a standard
container member because it doesn't have the copy semantics that the
standard containers require.

Ali


Ew. Thanks for the heads-up. :-)

(You can tell how often I use it. :-) )

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #21

P: n/a
Hi The Ghost In The Machine,

Even if your .CPP to .HTML syntax highlighter works,
I didn't like the .HTML code you showed me.

I know that mine works, and it works well,
and I prefer the HTML that it generates.

That C++ code of mine is at:
news:_J*************************@NCPlus.NET

Ghost, I think you mostly write server-side Java,
so C++ is not really your forte... No shame in that.

As I think you suggested, my children are in a dynamic array,
So I might have to do a memmove() to insert nodes,
Or maybe use qsort() on it... I haven't gotten that far yet.

Here's an example of how my tree routines might be called.
( Correcting some mistakes I made earlier )

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
{

// In the line below, the first call to Inc()
// creates one child ( * Lnk.P ) for Lnk
// ( Lnk is a global ) and returns a reference to it.
//
// That child ( * Lnk.P )
// is then is passed in a second call to InC(),
// which returns a reference to * Lnk.P->Lnk.P, a grandchild.
//
// There's no limit to the number of children per node.
//
// Afterwards Lnk.P->Lnk.P->Whatever
// is a valid int which is initialized to zero.

printf( "%d", Inc ( Inc ( Lnk ).Lnk ).Whatever );

// This prints all of Lnk's children.

LoopChildren printf( "%d, ", _Lnk->Whatever );

}

Here are the definitions...

// The - 1 below is so that I can pre-increment.

#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.P )

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// P is the Pointer to the NodeT being use.
// E is the End of an array NodeT's.
// Inc() allocates/increments P.

struct Lnk_T
{
Link B, P, E ;
};

struct NodeT
{
int Whatever ;
Lnk_T Lnk ;
};

Lnk_T Lnk ; // A global, so it's already initialized.

enum {
Sz_Node = sizeof NodeT
};

NodeT & Inc ( Lnk_T & Ln )
{
if ( Ln.E && ++ Ln.P < Ln.E )
return * Ln.P ;

// 4 nodes are created at a time, but this could be tweaked
// so that it grows by a certain percentage of Ln.P - Ln.B
int E = Ln.E - Ln.B + 4 ;
int P = Ln.P - Ln.B ;

Ln.B = ( Link ) realloc( Ln.B, E * Sz_Node );
Ln.E = Ln.B + E ;
Ln.P = Ln.B + P ;

memset( Ln.P, 0, ( Ln.E - Ln.P ) * Sz_Node );

return * Ln.P ;
}
Jul 22 '05 #22

P: n/a
Hi Karl Heinz Buchegger,

You think my C++ code would be easier to maintain
is I used more whitespace and longer identifiers ?

I don't agree at all.

You will never ever catch me telling someone that
his code is hard to maintain ( at least if I'm honest ).

I might well refuse to maintain someone's old code,
as I always prefer total rewrites.

Re: struct Lnk_T { Link B, P, E ; };

You commented: << Which only proves that
it is possible to write Fortran code in every language. >>

I actually own a 450 dollar copy of MS Fortran for Win98.
( From when I converted some Fortran code to C )

But I never used it, thank God... I refused to.

So I know what Fortran code ( and Fortran programmers )
look like ( with their big iron, IBM, and all that ).

I've seen those huge hard disk platters.

Hmm... Where they the forerunner to floppies ?
( Not counting tape, of course )
Jul 22 '05 #23

P: n/a
[snips]

On Fri, 30 Jul 2004 04:32:42 +0000, Jeff Relf wrote:
struct Lnk_T { Link B, E, Room ; };
struct NodeT { int Whatever ; Lnk_T Lnk ; };


Lnk_T? NodeT? Consistency is a good thing in programming.
Jul 22 '05 #24

P: n/a
On Sat, 31 Jul 2004 08:32:10 +0000, Jeff Relf wrote:
Hi Karl Heinz Buchegger,

You think my C++ code would be easier to maintain
is I used more whitespace and longer identifiers ?
If it were formatted for readability and used variables and other symbols
which themselves indicated their use, yes.
I might well refuse to maintain someone's old code,
as I always prefer total rewrites.


Not surprising, given your code. Most of us, however, don't see
reinventing the wheel as a good thing; if there's existing code which can
be modified to suit the task, rather than writing entirely new code, we do
it; it saves time, effort and bugs - the existing code is much more likely
to have been relatively debugged than the new code.

Writing unmaintainable code, as you do, does, indeed, make one want to
rewrite it.
Jul 22 '05 #25

P: n/a
Hi Kelsey Bjarnason,

Re: struct Lnk_T { Link B, E, Room ; };
struct NodeT { int Whatever ; Lnk_T Lnk ; };

You wrote: << Lnk_T ? NodeT ?
Consistency is a good thing in programming. >>

I'm currently favoring these two rules:
A. Place a capital T at the end of typedef identifiers.
B. If the T is preceded by a tall letter, such as a k,
then add an underscore in front of it.

But as I said before,
I sometimes like to change such rules
as it helps me review my code.

I'm now creating not only a forest of Usenet threads
but also a sorted array of Message-IDs,
linked to the nodes in that thread,
so that I can perform binary searches on them.

So I'm back to where I first started in this thread,
arrays of pointers to NodeT,
rather than arrays of NodeT.

struct NodeT ; typedef NodeT * Lnk_T ;

typedef Lnk_T * Lnk_Arr_T ;

typedef char * Line ; typedef Line * LineArr ;

struct NodeT { int LineArr Ln ; Lnk_Arr_T B, P, E ; };

NodeT Node ; // This is the forest of threads, a global.

In news:pa****************************@xxnospamyy.lig htspeed.bc.ca
You said: <<
There are times and places for typedefs;
a simple pointer type isn't one of them -
it obscures details which don't benefit from being obscured,
without bringing in any additional clarity. >>

I might agree with you
if you were referring to some else's code,
but when it's me that wrote the code
I prefer see: Line P ; rather than: char * P ;

And it's me that has do code the some of a bitch, not you.

You mentioned the Direct Draw 7...
it works, and it works quite well...
and that's all I care about.

I use the high-precision timer, QueryPerformanceCounter(),
to ensure that I never draw more often than
once every fiftieth of a second.

That gives me virtually instant scrolling.
not a nanosecond of delay due to drawing.

I just set a variable if something needs to be drawn,
( such as a cursor movement )
and then I paint the entire window...

I works like a dream.

X's window ( my newsreader ) is a maximized using:
SystemParametersInfo( SPI_GETWORKAREA, 0, ( RECT * ) R, 0 );
so it allows for the taskbar, and it is high-res.

You mentioned my:
#define Eq ! strcmp
#define Eqi ! stricmp
#define EqN ! strncmp
#define EqiN ! strnicmp

Saying: if ( Eq( P, "Hello" ) || Eq( P, "Good-bye" ) )

just looks better than:
if ( ! strcmp( P, "Hello" ) || ! strcmp( P, "Good-bye" ) )

You disagree ? Who cares ?

As for :
#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

That's the best piece of code I ever wrote.
Jul 22 '05 #26

P: n/a
In comp.os.linux.advocacy, Kelsey Bjarnason
<ke*****@xxnospamyy.lightspeed.bc.ca>
wrote
on Sun, 01 Aug 2004 13:18:26 -0700
<pa****************************@xxnospamyy.lightsp eed.bc.ca>:
On Sat, 31 Jul 2004 08:32:10 +0000, Jeff Relf wrote:
Hi Karl Heinz Buchegger,

You think my C++ code would be easier to maintain
is I used more whitespace and longer identifiers ?


If it were formatted for readability and used variables and other symbols
which themselves indicated their use, yes.
I might well refuse to maintain someone's old code,
as I always prefer total rewrites.


Not surprising, given your code. Most of us, however, don't see
reinventing the wheel as a good thing; if there's existing code which can
be modified to suit the task, rather than writing entirely new code, we do
it; it saves time, effort and bugs - the existing code is much more likely
to have been relatively debugged than the new code.

Writing unmaintainable code, as you do, does, indeed, make one want to
rewrite it.


I for one would be curious as to whether someone's developed
a tool that would allow for the management of unreadable C
code.

Something along the lines of Eclipse, perhaps?

Anyway, the capabilities that I might find useful are these:

[1] "De-macroization" of function calls and identifiers. Basically,
it would either expand by one level or down to standard macros.
More on "standard macros" later on.

[2] Replacement of local variable names. If I see a 'c', I can replace
it with 'local_speed_of_light'. (That's a bit contrived but you
get the idea.) No other instances of 'c' out of the scope would
be affected.

[3] Replacement of global variable names. This one's a bit trickier
and would require that the development environment know a lot
more about the system under development -- every module would
have to be looked at. One other possibility: conversion of a global
variable to a static scoped classfield name:

x => Y::z

and inclusion somewhere of:
class Y { public: static int z; }
int Y::z = 0;

Or even a non-static accessor function:

x => Y::singleton_y().z()
class Y { public: static Y & singleton_y(); int z(); }
Y & Y::singleton_y() { ... }
int Y::z() { ... }

[4] Elimination of unnecessary #includes, and proper guardbanding of
user #includes and certain system #includes.

[5] Identification of standard macros such as 'getchar', 'EOF', and
'FD_SET', so that they don't get de-macroized in [1]. Shadowing
of macros would be properly detected.

[6] Of course it should prettyprint. There are a few issues here, mostly
of the "which scheme did you like?" type.

[7] Auto-docstubbing. Basically, declarations of the type:

int x,y,z,w;

would be replaced by:

int x; // TODO: what is x?
int y; // TODO: what is y?
int z; // TODO: what is z?
int w; // TODO: what is w?

One could also extend parameter lists, either old- or new-style.

a(int b, int c) =>
a(
int b, // TODO: what is b?
int c // TODO: what is c?
)

Of course variable and parameter lists with existing documentation
would be unaffected.

[8] Something along the lines of javadoc or Cweb, for generation
of documentation from the codebase. Ideally, the reverse would
also be possible but most Marketing departments won't be
technical enough to get the formatting quite right. (It's an
interdepartmental negotiation process in any event.)

[9] If I need a system macro or function, the system would at my
behest include the relevant #include file, if it's not already there
(or #included by some other #include file I already have).
This could also be extended to include user-defined stuff
as well.

[10] All of this would be nicely visual. KDevelop isn't too bad as
a starting point, for example, though I can't say I like some
of Qt's hacks.

[11] Detection of loop-local variables, and the replacement of:

int i;

for(i = 0; ...) {
}

with

for(int i = 0; ...) {
}

if 'i' is used nowhere else in the module.

[12] A capability similar to [3] except for addition, renaming, and
possibly even deletion of base-level virtuals.

[13] Methods by which one can splice and merge class hierarchy,
by creating a new base or derived class and then moving methods
and fields around. The constructors and accessors would do the
right thing.

[14] A method by which one can move virtuals, leaving a "ghost"
(pure virtual) in the right place.

[15] A method by which one can replace pointer declarations with a
"smart pointer", and a simple template for declaring "smart pointers".
There are admittedly a few ugly issues here (my implementation
of "smart pointers" requires two friend declarations, for example,
and requires an extra int to manage the refcount).

[16] Individual, group, and company-wide policy declarations to manage
all this.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #27

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 31 Jul 2004 07:22:00 GMT
<_J*************************@NCPlus.NET>:
Hi The Ghost In The Machine,

Even if your .CPP to .HTML syntax highlighter works,
I didn't like the .HTML code you showed me.
Your perogative, of course.

I know that mine works, and it works well,
and I prefer the HTML that it generates.

That C++ code of mine is at:
news:_J*************************@NCPlus.NET

Ghost, I think you mostly write server-side Java,
so C++ is not really your forte... No shame in that.
At least my C++ is readable. Also, I've worked with
C++ since my introduction thereto in the late 80's/
early 90's. I still remember assigning to "this" as
a tool -- which was thankfully removed later on -- and
the staged compile from C++ to C using AT&T's cfront, which
was also removed later on. GCC came later, and now --
finally -- GCC understands namespaces.

STL is one of C++'s prettier efforts, although I'm not
entirely certain as to the philosophy, which tries to
separate:

implementation
data store
and a third thing which I forget now, though it might be
something along the lines of collection type.

The same code, in particular, should work for a std::set as
for a std::list or a std::vector -- and, it turns out,
it does, if written properly.

As I think you suggested, my children are in a dynamic array,
So I might have to do a memmove() to insert nodes,
Or maybe use qsort() on it... I haven't gotten that far yet.
Gad, such ugly details for what should be a nice, abstract
collection.

Here's an example of how my tree routines might be called.
( Correcting some mistakes I made earlier )

__stdcall WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
Ew, Windowsite. :-)
{

// In the line below, the first call to Inc()
// creates one child ( * Lnk.P ) for Lnk
// ( Lnk is a global ) and returns a reference to it.
//
// That child ( * Lnk.P )
// is then is passed in a second call to InC(),
// which returns a reference to * Lnk.P->Lnk.P, a grandchild.
//
// There's no limit to the number of children per node.
//
// Afterwards Lnk.P->Lnk.P->Whatever
// is a valid int which is initialized to zero.

printf( "%d", Inc ( Inc ( Lnk ).Lnk ).Whatever );

// This prints all of Lnk's children.

LoopChildren printf( "%d, ", _Lnk->Whatever );

}

Here are the definitions...

// The - 1 below is so that I can pre-increment.

#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.P )
Now that's just absolutely dis-GUST-ing. Suppose, for
example, you had a collection of collections? (Rare,
but it happens.)

Also, you could just do

while(_Lnk < Lnk.P) _Lnk++;

though it depends on whether you've looked at the assembly
output or not to see which method's more efficient.

A good optimizing compiler won't care anyway.

struct NodeT ;

typedef NodeT * Link ;

// B is the Beginning of an array of NodeT's.
// P is the Pointer to the NodeT being use.
// E is the End of an array NodeT's.
// Inc() allocates/increments P.

struct Lnk_T
{
Link B, P, E ;
};

struct NodeT
{
int Whatever ;
Pointers don't fit in ints anymore. :-)
Lnk_T Lnk ;
};

Lnk_T Lnk ; // A global, so it's already initialized.

enum {
Sz_Node = sizeof NodeT
};

NodeT & Inc ( Lnk_T & Ln )
{
if ( Ln.E && ++ Ln.P < Ln.E )
return * Ln.P ;

// 4 nodes are created at a time, but this could be tweaked
// so that it grows by a certain percentage of Ln.P - Ln.B
int E = Ln.E - Ln.B + 4 ;
int P = Ln.P - Ln.B ;

Ln.B = ( Link ) realloc( Ln.B, E * Sz_Node );
Ln.E = Ln.B + E ;
Ln.P = Ln.B + P ;

memset( Ln.P, 0, ( Ln.E - Ln.P ) * Sz_Node );

return * Ln.P ;
}


And suppose I want to cluster my allocations 8 to a page?
For that matter, how about allocating an entire page? Memory
faults are a problem.

(In STL such details are pushed to an Allocator or Allocation
sublayer -- I forget which. I rarely use it. realloc() is
a problem waiting to happen on C++ classes, if not used
properly.)

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #28

P: n/a
In comp.os.linux.advocacy, Kelsey Bjarnason
<ke*****@xxnospamyy.lightspeed.bc.ca>
wrote
on Sun, 01 Aug 2004 13:11:49 -0700
<pa****************************@xxnospamyy.lightsp eed.bc.ca>:
[snips]

On Fri, 30 Jul 2004 04:32:42 +0000, Jeff Relf wrote:
struct Lnk_T { Link B, E, Room ; };
struct NodeT { int Whatever ; Lnk_T Lnk ; };


Lnk_T? NodeT? Consistency is a good thing in programming.


Assumine anyone even wants to pursue this already-solved problem.
Herewith examples of processing things in STL.

The "explicit typedef/for loop" way.

#include <list>

class C { public: C() {...} ... };

typedef std::list<C> list_of_things_type;
list_of_things_type list_of_things;

void routine() {

/* ... */

for(list_of_things_type::const_iterator i = list_of_things.begin();
i != list_of_things.end(); i++)
{
const C & obj = *i;
/* ... obj ... */
}

Or, if one wants to,

#include <algorithm>
#include <list>

class C { public: C() {...} ... };

std::list<C> list_of_things;

void func(const C & obj)
{
/* ... */
}

class D { public: void operator()(C const & obj) { ... } };
D dobj;

void routine() {

/* ... */

std::for_each(list_of_things.begin(), list_of_things.end(), func);
std::for_each(list_of_things.begin(), list_of_things.end(), dobj);

}

which evokes memories of LISP's apply(), for those so inclined.

If one replaces std::list<> with std::vector<>, std::set<>,
or std::hashset<> -- the code changes are minimal, limited
only to the declaration. std::map<> and std::hashmap<>
require a little work, mostly because the iterator
returns a pair of items (key/value). But std::set<> takes
as one of its template arguments a comparison method, which
means that the collection can be in any order the programmer wants,
automatically maintained as objects are added or removed.

Compared to this level of elegance, Jeff's code is, in the
considered opinion of this particular C++ programmer,
swamp muck. :-P~~~

Not that this is a perfect solution, mind you; there are some
constructs in C++/STL that are downright ugly. Try writing
the following loop using std::find(), for example.

typedef std::map<std::string, C, std::less<std::string> > things_map_type;
things_map_type things_map;

/* ... */

for(things_map_type::const_iterator i = things_map.begin();
i != things_map.end(); i++)
{
const C & key = (*i).first;
const C & val = (*i).second;
if(!val.isDesirable())
break;
}

The best I can do is something using std::unary_negate<> and _Select2nd,
and I'm not sure that's quite kosher -- or even right. Yuck.

But at least C++/STL can do it; in Java one would probably have to
leave the loop as is. (Java does offer Arrays.binarySearch()
and Collections.binarySearch(), but both assume already-sorted
collections (either an array or a list).)

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #29

P: n/a
Hi The Ghost In The Machine,

You wrote: <<
I for one would be curious as to
whether someone's developed a tool that would allow for
the management of unreadable C code. >>
Unreadable C code ?

Don't you mean code that you don't Want to read ?

You wrote: <<
Something along the lines of Eclipse, perhaps ? Anyway,
the capabilities that I might find useful are these:... >>

I know nothing about Eclipse,
but I am curious as to who exactly would want a machine
to control so many aspects of one's source code.

Certainly not a real programmer, I assume.

You wrote: << [ 16 ]
Individual, group, and company-wide policy declarations... >>

Shudder... I'll pass on that, thanks anyways.

Actually pounding out code is a piece of cake,
designing it is the main problem... as they say:
The Devil is in the details.

For my own review,
and for anyone else who might enjoy glancing at it ( ha ! ),
I've included some code snippets below,
describing my newsreader's threaded and unthreaded mode.

Why didn't I write this weeks ( months ) ago ?
Mostly because of my vast indecision...
I can't decide how I want the interface to look...
( and my mind wanders off too )

After spending many days thinking about it in these newsgroups
including several hours punching it in
( first one way, then the other ) ...

once I hit build,
it actually ran as designed, with only a few minor typos.

But that's the problem...
it's running as I designed it,
And I'm not sure what I want it to do.

For clarity ( ha ! ), some of the code is out of sequence.

Here are some globals:

Ln_T Ln ; // This holds the dynamic array of lines,
// i.e. the screen.

NodeT Forest, Flat ; // Threaded and unthreaded views.

// This is an abriviated list of headers.
// ( They are indexes for an array of lines )

enum { _Score, _Date, _Path, _Reader, _Name,
_XRefs, _Subj, _MID, _Par, _Par2, _Par3, _Par4, _Par5, _Lns };

Somwhere in WinMain()'s event loop...

// Deletes the old forest, and it's flat view.

DeC ( & Forest ); Zero( Forest );

free ( Flat.B ); Zero( Flat );

// Loops backwards though an array of lines
// containing a list of abriviated headers
// in the reverse order as that found on the server.
// ( Yes, that's a double reverse beause I store
// the headers in reverse order )

LoopR { Line Par = _Ln [ _Par ];

// Posts are assigned a single letter score,
// from 0-9, A-Z, a-Z

char & C = * _Ln [ _Score ] ;

// I get zero, replies to me are 1-5, based on proximity.

Loop ( 6 ) if ( EqN ( _Ln [ _MID + J ], "_Jeff", 5 ) ) {
C = '0' + J ; goto Done; }

if ( NID ("l7Um" ) || NID ( "pejU" ) ) C = 'A' ; else {
Line Pat = "server.com"; int PatL = strlen ( Pat );
Line B = _Ln [ _MID ], Cmp = strchr( B, 0 ) - PatL ;
if ( Cmp >= B && EqN ( Cmp, Pat, PatL ) ) C = 'B' ; else

// Titles starting without "Re: " get a C.

if ( ! EqN ( _Ln [ _Subj ], "Re: ", 4 ) ) C = 'C' ; else
C = 'N' ; } Done:

// Post has no parent, so it's at the top level.

if ( ! * Par ) AllocN( & Forest )

// Looks for the parents Message-ID in the unthreaded list.
// ( Which is just an array of links to the threaded list )

LoopC ( & Flat )
if ( Eq ( Par, ( * Arr )->Ln [ _MID ] ) ) break ;

// The parent was not found, so put it at the top level.

if ( Arr > Flat.P ) AllocN( & Forest )

// Make it * Arr's child.

AllocN( * Arr ) }

// This rolls back the array of lines,
// because they now reside only in the forest.

Ln.P = Ln.B + I_Cook - 1 ;

// This prints out the messsages in a threaded view.
// ( Much work must be done here )

PrnC( & Forest, 0 );

.......

DeC ( Lnk_T Lnk ) { if ( ! Lnk->B ) return ;
LoopC ( Lnk ) { Lnk_T P = * Arr ;

// Recursively deletes... how fun.

DeC ( P );

// Deletes the array of lines that contain
// the abreviated headers.

LineArr Ln = P->Ln - 1 ;
Loop( _Lns ) free ( * ++ Ln ); free ( P ); }

free ( Lnk->B ); }
PrnC ( Lnk_T Lnk, int Lv ) { if ( ! Lnk->B ) return ;
LoopCR ( Lnk ) { Lnk_T P = * Arr ;

// Prints recursively.

PrnC ( P, Lv + 1 ); LineArr & Ln = P->Ln ;

// Dumps the contents of a node ( a message ).

Sh( "%s %d %s, %s, %s, %s\n %s\n %s\n %s",
Ln [ _Score ], Lv, Ln [ _Date ], Ln [ _Path ],
Ln [ _Reader ], Ln [ _Name ], Ln [ _XRefs ],
Ln [ _MID ], Ln [ _Subj ] ); } }
// THis grows a parent's list of children ( unlimited ).

Lnk_T & Inc ( Lnk_T Lnk ) {

// No need to allocate a new pointer

if ( Lnk->B && ++ Lnk->P < Lnk->E ) return * Lnk->P ;

// Give me 40 new pointers

int E = Lnk->E - Lnk->B + 40, P = Lnk->P - Lnk->B ;
Lnk->B = ( Lnk_Arr_T ) realloc( Lnk->B, E * Sz_Ptr );

// Initialize the newest pointers

Lnk->E = Lnk->B + E ; Lnk->P = Lnk->B + P ;
memset( Lnk->P, 0, ( Lnk->E - Lnk->P ) * Sz_Ptr );

return * Lnk->P ; }

.....
typedef char * Line ;

typedef Line * LineArr ;

struct Ln_T { LineArr B, P, E ; };

struct NodeT ; typedef NodeT * Lnk_T ;

typedef Lnk_T * Lnk_Arr_T ;

struct NodeT { LineArr Ln ; Lnk_Arr_T B, P, E ; };

#define Zero( X ) memset( & X, 0, sizeof X );

#define AllocN( Lnk ) { Lnk_T & P = Inc ( Lnk ); \
P = ( Lnk_T ) malloc( sizeof NodeT ); rv = _Lns * Sz_Ptr ; \
memmove( P->Ln = ( LineArr ) malloc( rv ), _Ln, rv ); \
memset( _Ln, 0, rv ); \
P->B = P->P = P->E = 0 ; Inc ( & Flat ) = P ; continue; }

#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

#define LoopR LineArr B = Ln.B + I_Cook - 1, \
_Ln = ! Ln.B ? B : Ln.P + 1 ; while ( ( _Ln -= _Lns ) > B )

#define LoopC( Lnk ) Lnk_T _Lnk = Lnk ; \
Lnk_Arr_T E = _Lnk->P + 1, \
Arr = ! _Lnk->B ? E : _Lnk->B - 1 ; while ( ++ Arr < E )

#define LoopCR( Lnk ) Lnk_T _Lnk = Lnk ; \
Lnk_Arr_T B = _Lnk->B - 1, \
Arr = ! _Lnk->B ? B : _Lnk->P + 1 ; while ( -- Arr > B )
Jul 22 '05 #30

P: n/a
Hi Kelsey Bjarnason,

Re:
#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

You commented: << Marvellous; symbol clashes,
just because you use this macro twice in the same scope.
Talk about badly-written. >>

You're worried about compilation errors ?

Real programmers are Never concerned about that.

This code compiles, and it does just what I would expect:

FuBar () { int X = -1, Y = -1 ;

Loop ( 6 ) { ++ X ; Loop ( 7 ) ++ Y ; }

// Prints: 5 and 6

printf ( " %d and %d ", X, Y ); }

You wrote: <<
Do us a favour: never, ever, post your code anywhere again.
Some poor unsuspecting soul might think
you know what you're doing and try to mimic you. >>

Call me an ignorant idiot ( yet again ),
but I, for one, don't think you're a Real programmer.

I started coding HP-67 calculators
( with the magnetic strips ) back in 1976.

Programming has been my sole profession since the start of 1982,
and, as you can see, I'm building my own newsreader...

So it's also my hobby.

I wrote: << I know nothing about Eclipse,
but I am curious as to who exactly would want a machine
to control so many aspects of one's source code. >>

And you replied: << To automate converting code such as yours
into something sane. >>

Now I know you're not a programmer,
changing the whitespace, macros and such
is a really good way to familiarize yourself with the code.

That's why I sometimes do that to my own code.
( e.g. Stuff I wrote 12 years ago )
Jul 22 '05 #31

P: n/a
Jeff Relf wrote:
Hi Kelsey Bjarnason,

Re:
#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

You commented: << Marvellous; symbol clashes,
just because you use this macro twice in the same scope.
Talk about badly-written. >>

You're worried about compilation errors ?

Real programmers are Never concerned about that.


Real programmers don't piss their colleagues off. They write clear, simple,
robust, and easily-changed code. This helps keep their colleagues in the ...
loop.

--
Phlip
http://industrialxp.org/community/bi...UserInterfaces
Jul 22 '05 #32

P: n/a
Hi The Ghost In The Machine,

You showed something like this:

for ( list_of_things_type::const_iterator
i = list_of_things.begin();
i != list_of_things.end();
i ++ )
{ const C & obj = *i;
/* ... obj ... */
}

And then you commented: <<
Compared to this level of elegance, Jeff's code is,
in the considered opinion of this particular C++ programmer,
swamp muck. :-P~~~ >>

Are you really a C++ programmer ? I don't think so.

Java maybe, server side perhaps,
but you're not a serious Win XP C++ programmer.

You want to make comparisons ?

This is how I loop through a list of unthread Usenet messages:
( From news:_J************************@NCPlus.NET )

LoopC ( & Flat )
if ( Eq ( Par, ( * Arr )->Ln [ _MID ] ) ) break ;

This is how I delete a forest of threaded messages:

DeC ( Lnk_T Lnk ) { if ( ! Lnk->B ) return ;
LoopC ( Lnk ) { Lnk_T P = * Arr ;

// Recursively deletes... how fun.

DeC ( P );

// Deletes the array of lines that contain
// the abbreviated headers.

LineArr Ln = P->Ln - 1 ;
Loop( _Lns ) free ( * ++ Ln ); free ( P ); }

free ( Lnk->B ); }

I'm looking at your way... and my way...

I'm comparing the two, and I'm very much preferring my way.

By the way...

People are Still inventing wheels... as they well should.

It's called: A better tire.
Jul 22 '05 #33

P: n/a
Jeff Relf wrote:

Hi The Ghost In The Machine,


_____________________
/| /| | |
||__|| | Please do not |
/ O O\__ | feed the |
/ \ | Trolls |
/ \ \|_____________________|
/ _ \ \ ||
/ |\____\ \ ||
/ | | | |\____/ ||
/ \|_|_|/ | _||
/ / \ |____| ||
/ | | | --|
| | | |____ --|
* _ | |_|_|_| | \-/
*-- _--\ _ \ | ||
/ _ \\ | / `
* / \_ /- | | |
* ___ c_c_c_C/ \C_c_c_c____________
--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #34

P: n/a
Hi The Ghost In The Machine,

Re:
#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.P )

You wrote: << Also, you could just do

while(_Lnk < Lnk.P) _Lnk++;

though it depends on whether you've looked at the assembly
output or not to see which method's more efficient. >>

No, you missed one of the main reasons for LoopChildren:

It pre-increments. ( Hence the initial -1 )

Your alternatives, mentioned in your other posts,
all used post-increments, which I don't like.

The other reason for defining something like LoopChildren
is how clean it makes the code look.

For an example of that, see my other post:
news:_J************************@NCPlus.NET

You mentioned:
" Pointers don't fit in ints anymore. :-) "

I don't ever do that, never did.

All the code that I showed used:

typedef char * Line ;

enum { Sz_Ptr = sizeof Line };

Slap that on a 64-bit computer, and is still works...

I know because I've done this before.

Re: Memory faults,

You asked: <<
And suppose I want to cluster my allocations 8 to a page ?
For that matter, how about allocating an entire page ?
Memory faults are a problem. >>
...
<< ...realloc() is a problem waiting to happen on C++ classes,
if not used properly. >>

My memory usage is not very taxing at all.

I'm not writing a fault-tolerant server
that supports terabytes of data
and has to remain up for months on end.

At any rate,
I'm no longer using the code you were referring to.

Now I only allocate dynamic arrays of pointers,
not nodes...

But even that node that you were referring to was tiny,
just an int and three pointers,
it was not designed to be large.

Jul 22 '05 #35

P: n/a
Hi Karl Heinz Buchegger,

Re: The Ghost In The Machine and me,

You wrote: <<
_____________________
/| /| | |
||__|| | Please do not |
/ O O\__ | feed the |
/ \ | Trolls |
/ \ \|_____________________|
/ _ \ \ ||
/ |\____\ \ ||
/ | | | |\____/ ||
/ \|_|_|/ | _||
/ / \ |____| ||
/ | | | --|
| | | |____ --|
* _ | |_|_|_| | \-/
*-- _--\ _ \ | ||
/ _ \\ | / `
* / \_ /- | | |
* ___ c_c_c_C/ \C_c_c_c____________


At least we're talking abut C++, doesn't that count ?

I don't think the Ghost is a troll,
I just think he has a different point of view from me.

A lot of people have scored me down too,
but that's fine with me...

I'm not entering anyone's popularity contest.

It's even possible that
The Ghost and I could come to a understanding.

There's so much miscommunication on Usenet...

Why not try to resolve some of it ?
Jul 22 '05 #36

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 3 Aug 2004 05:19:46 GMT
<_J************************@NCPlus.NET>:
Hi Kelsey Bjarnason,

Re:
#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

You commented: << Marvellous; symbol clashes,
just because you use this macro twice in the same scope.
Talk about badly-written. >>

You're worried about compilation errors ?

Real programmers are Never concerned about that.

This code compiles, and it does just what I would expect:

FuBar () { int X = -1, Y = -1 ;

Loop ( 6 ) { ++ X ; Loop ( 7 ) ++ Y ; }

// Prints: 5 and 6

printf ( " %d and %d ", X, Y ); }
Bleah.

Maybe what *you* expect. However, if one were to try to
convert it into a more elegant version of C++, inner loops
and all:

#include <stdio.h>
int main(int, char **)
{
int x = -1;
int y = -1;

for(int i = 0; i < 6; i++)
{
x++;
for(int j = 0; j < 7; j++)
y++;
}

printf("%d %d\n", x,y);
}

the results would be quite different -- and in fact
you've posted a bug -- a bad comment, for the most part.

Unless you meant

{ Loop (6) { ++X; } } { Loop (7) { ++Y; } }

which is what would be required to avoid naming collisions.

(The results I get are 5 and 41, before and after conversion.
This is regardless of whether I use 'i' or 'j' as the inner
variable, which shadows the outer one.)

You wrote: <<
Do us a favour: never, ever, post your code anywhere again.
Some poor unsuspecting soul might think
you know what you're doing and try to mimic you. >>

Call me an ignorant idiot ( yet again ),
but I, for one, don't think you're a Real programmer.
"Real" is a weird way of putting it.

I started coding HP-67 calculators
( with the magnetic strips ) back in 1976.
I started with a Wang, perhaps, back in '74 or thereabouts.
So there. :-P

Programming has been my sole profession since the start of 1982,
and, as you can see, I'm building my own newsreader...
I've done RFC977 work. It's rather interesting, actually.

(No, you don't really want to know why. Suffice it to say
it was a phase many young males go through.)

So it's also my hobby.

I wrote: << I know nothing about Eclipse,
but I am curious as to who exactly would want a machine
to control so many aspects of one's source code. >>

And you replied: << To automate converting code such as yours
into something sane. >>

Now I know you're not a programmer,
changing the whitespace, macros and such
is a really good way to familiarize yourself with the code.

That's why I sometimes do that to my own code.
( e.g. Stuff I wrote 12 years ago )


I'm surprised you can read that gunk.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #37

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 3 Aug 2004 10:03:42 GMT
<_J************************@NCPlus.NET>:
Hi The Ghost In The Machine,

Re:
#define LoopChildren \
Link _Lnk = Lnk.B - 1 ; while ( ++ _Lnk < Lnk.P )

You wrote: << Also, you could just do

while(_Lnk < Lnk.P) _Lnk++;

though it depends on whether you've looked at the assembly
output or not to see which method's more efficient. >>

No, you missed one of the main reasons for LoopChildren:

It pre-increments. ( Hence the initial -1 )

Your alternatives, mentioned in your other posts,
all used post-increments, which I don't like.
Your perogative. Personally, I think of preincr and postincr
as where one puts the 'INC Rx' instruction (or perhaps the
'INC memaddr' instruction, depending on compiler sophistication).

I write

for(int i = 0; i < n; i++)

but others might write

for(int i = 1; i <= n; ++i)

which works equally well except for the one-off.

The other reason for defining something like LoopChildren
is how clean it makes the code look.
Noooooo comment!

For an example of that, see my other post:
news:_J************************@NCPlus.NET

You mentioned:
" Pointers don't fit in ints anymore. :-) "

I don't ever do that, never did.
Good.

All the code that I showed used:

typedef char * Line ;

enum { Sz_Ptr = sizeof Line };

Slap that on a 64-bit computer, and is still works...

I know because I've done this before.

Re: Memory faults,

You asked: <<
And suppose I want to cluster my allocations 8 to a page ?
For that matter, how about allocating an entire page ?
Memory faults are a problem. >>
...
<< ...realloc() is a problem waiting to happen on C++ classes,
if not used properly. >>

My memory usage is not very taxing at all.
No, but suppose you had N different listtypes?

Also, on an overloaded system, you'll feel it; a cheapie
page fault takes on the order of a few hundreds of nanoseconds,
but a pricey one will take a few milliseconds, as it reads
from swap.

I'm not writing a fault-tolerant server
that supports terabytes of data
and has to remain up for months on end.
Perhaps you should. :-)

At any rate,
I'm no longer using the code you were referring to.

Now I only allocate dynamic arrays of pointers,
not nodes...

But even that node that you were referring to was tiny,
just an int and three pointers,
it was not designed to be large.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #38

P: n/a
In comp.os.linux.advocacy, Karl Heinz Buchegger
<kb******@gascad.at>
wrote
on Tue, 03 Aug 2004 11:34:43 +0200
<41***************@gascad.at>:
Jeff Relf wrote:

Hi The Ghost In The Machine,


_____________________
/| /| | |
||__|| | Please do not |
/ O O\__ | feed the |
/ \ | Trolls |
/ \ \|_____________________|
/ _ \ \ ||
/ |\____\ \ ||
/ | | | |\____/ ||
/ \|_|_|/ | _||
/ / \ |____| ||
/ | | | --|
| | | |____ --|
* _ | |_|_|_| | \-/
*-- _--\ _ \ | ||
/ _ \\ | / `
* / \_ /- | | |
* ___ c_c_c_C/ \C_c_c_c____________


Hmph. Well, if you insist. :-)

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #39

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 3 Aug 2004 09:30:40 GMT
<_J************************@NCPlus.NET>:
Hi The Ghost In The Machine,

You showed something like this:

for ( list_of_things_type::const_iterator
i = list_of_things.begin();
i != list_of_things.end();
i ++ )
{ const C & obj = *i;
/* ... obj ... */
}

And then you commented: <<
Compared to this level of elegance, Jeff's code is,
in the considered opinion of this particular C++ programmer,
swamp muck. :-P~~~ >>

Are you really a C++ programmer ? I don't think so.
At least I know about C++/STL.

Java maybe, server side perhaps,
but you're not a serious Win XP C++ programmer.

You want to make comparisons ?

This is how I loop through a list of unthread Usenet messages:
( From news:_J************************@NCPlus.NET )

LoopC ( & Flat )
if ( Eq ( Par, ( * Arr )->Ln [ _MID ] ) ) break ;
If one assumes the declarations

typedef std::string itemtype; // or whatever you want
typedef std::xxx<itemtype> collectiontype;
// xxx = set, vector, or list
collectiontype collection;
collectiontype::const_iterator it;

then one can do the following.

it = std::find(collection.begin(), collection.end(), "constant");
or
it = std::binary_search(collection.begin(), collection.end(), "constant");
or
inline bool myfunc(itemtype conts & val) { return val == "constant"; }
it = std::find_if(collection.begin(), collection.end(), myfunc);
or[*]
it = std::find_if(collection.begin(), collection.end(),
std::bind2nd(std::equal_to<itemtype>, "constant"));

depending on whether one has a value or a function, and whether
the collection's sorted or not. While the declarations take some
time to use properly, it should be fairly clear what I'm doing.

If the collection is a std::set<> with itemtype as the key, one can
also ask

it = collection.find(val);

which is probably simpler.

To save some typing, one can also prefix the source file with

'using namespace std;'

but I for one am not overly fond of that approach;
I prefer using 'std::' so that I can find STL usages the code.

Now, after one's assigned a value to 'it', one can then test 'it':

if(it != collection.end())
/* found it */
else
/* not in there */

or one can do inline tests such as:

if((it = collection.find("constant")) != collection.end())
/* do something with '*it' */
else
/* collection doesn't contain "constant" */

The inline assignment should be familiar to most C programmers.

One can consider 'it' a 'super-pointer', generalizing the concept
of a pointer and allowing for some nice operations. For instance,
one can remove the pointer:

collection.erase(it);

and the collection will no longer contain that item.

Dereferencing a non-end pointer ('*it') will get the item back.

This is how I delete a forest of threaded messages:

DeC ( Lnk_T Lnk ) { if ( ! Lnk->B ) return ;
LoopC ( Lnk ) { Lnk_T P = * Arr ;

// Recursively deletes... how fun.

DeC ( P );

// Deletes the array of lines that contain
// the abbreviated headers.

LineArr Ln = P->Ln - 1 ;
Loop( _Lns ) free ( * ++ Ln ); free ( P ); }

free ( Lnk->B ); }
collection.erase(collection.begin(), collection.end());

or just let collection go out of scope. If one wants an
explicit forest of items some work will be required to
encapsulate them properly. I have a "smartpointer" class
that contains an explicit refcount, but that does take
more space.

I'm looking at your way... and my way...

I'm comparing the two, and I'm very much preferring my way.
Your perogative. I'll say this for your way of coding:
you're close to the hot metal. However, you're also
making it ugly on yourself as you're touching the oil,
trying not to get burned by various syntactic issues,
dancing all around because of the heat, etc.

By the way...

People are Still inventing wheels... as they well should.

It's called: A better tire.


Enjoy your swamp muck, and watch out for the road tacks. :-)
[*] This is where C++/STL starts to get a bit messy, but
std::equal_to is far more general than testfunc() -- presumably
this is documented somewhere, if only in bits/stl_algo.h
or bits/stl_function.h; note that those are included
indirectly and the user should #include <algorithm>
or #include <functional> instead.

There's a method to take a collection type and get the
type of its argument -- collectiontype::value_type
is suggested in the #include files -- if one doesn't
explicitly declare itemtype. For std::map and std::hashmap,
one can also use collectiontype::key_type.

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #40

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 3 Aug 2004 10:22:39 GMT
<_J************************@NCPlus.NET>:
Hi Karl Heinz Buchegger,

Re: The Ghost In The Machine and me,

You wrote: <<
_____________________
/| /| | |
||__|| | Please do not |
/ O O\__ | feed the |
/ \ | Trolls |
/ \ \|_____________________|
/ _ \ \ ||
/ |\____\ \ ||
/ | | | |\____/ ||
/ \|_|_|/ | _||
/ / \ |____| ||
/ | | | --|
| | | |____ --|
* _ | |_|_|_| | \-/
*-- _--\ _ \ | ||
/ _ \\ | / `
* / \_ /- | | |
* ___ c_c_c_C/ \C_c_c_c____________

At least we're talking abut C++, doesn't that count ?

I don't think the Ghost is a troll,
I just think he has a different point of view from me.


Very different. :-)

A lot of people have scored me down too,
but that's fine with me...

I'm not entering anyone's popularity contest.

It's even possible that
The Ghost and I could come to a understanding.
I understand you well enough. Admittedly, there are
those out there who think nothing of putting
no comments at all into swamp muck, codeswill, or
execrable crap, then using it as the documentation
basis for whatever the tool is supposed to do.

(The computer has no problem understanding Obfuscated C.
But mere mortals have to take it apart. Code should
be understandable to both man and machine -- ideally.)

Of course part of my position is self-defense. I write
something, come back to it later, and wonder why the
hell I wrote it that particular way. It behooves me
to be able to read my own code -- and presumably that
means others can at least have a chance of decoding
what I scribbled into the computer at some point.

ObLinux: I can get the source code. That is a plus in itself.

There's so much miscommunication on Usenet...

Why not try to resolve some of it ?

--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #41

P: n/a
Hi The Ghost In The Machine,

Oops, I showed: <<
FuBar () { int X = -1, Y = -1 ;

Loop ( 6 ) { ++ X ; Loop ( 7 ) ++ Y ; }

// Prints: 5 and 6

printf ( " %d and %d ", X, Y ); }


And you correctly corrected me: <<
The results I get are 5 and 41, before and after conversion.
This is regardless of whether I use 'i' or 'j'
as the inner variable, which shadows the outer one. >>

I meant to write this:

FuBar () { int X = -1, Y = -1 ;

{ Loop ( 6 ) ++ X ; } Loop ( 7 ) ++ Y ;

// Prints: 5 and 6

printf ( " %d and %d ", X, Y ); }
I say that this: { Loop ( 6 ) ++ X ; } Loop ( 7 ) ++ Y ;
is more readable than this:

for(int i = 0; i < 6; i++)
{
x++;
for(int j = 0; j < 7; j++)
y++;
}

You commented: " I'm surprised you can read that gunk. "

That only goes to show that
one man's meat is another man's poison.

I'm into targeting Win XP for personal use,
( I put the personal in personal computer )...

and you're into targeting servers in a large corporation...

As the saying goes:

I'm ok, you're ok,
and Microsoft should give us a 75 billion dollar rebate.
Jul 22 '05 #42

P: n/a
Hi The Ghost In The Machine,

You showed: <<
it = std::binary_search(
collection.begin(), collection.end(), "constant");

Yea, my original plan was to :

A. qsort() the unthread list of Usenet messages ( Flat ).
( Flat contains one huge array of pointers to nodes,
as described here
news:_J************************@NCPlus.NET )

B. Then do a binary search on it.

But then I ran the code... No need for the binary search.

It's already instant,

even with a list of two thousand messages.
( Even more so when compared to how long it takes me
to download those messages using a spotty dial-up service )

In fact, it's much much Much faster than 40Tude Dialog,
the newsreader that I was using before I wrote X.
( Actually, I'm still using Dialog for some things,
because X is still so primitive )

Re: Your code:
typedef std::string itemtype; // or whatever you want
typedef std::xxx<itemtype> collectiontype;
// xxx = set, vector, or list
collectiontype collection;
collectiontype::const_iterator it;

You said: " ...it should be fairly clear what I'm doing. "

Yes, it is quite clear ( and quite interesting too ).

You showed: <<
Now, after one's assigned a value to 'it',
one can then test 'it':

if ( it != collection.end() ) /* found it */


Of course, I do that all the time...

Only I say this: if ( J < LLL ) // found, i.e. broke out.

after: Loop( 5 ) if ( Eq( "Hello", Line_Array[ J ] ) ) break;

where: #define Eq ! strcmp

#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

The main difference is that I'm using J, not " it ",
and LLL, not collection.end() .

Re: collection.erase( it );

With my dynamic arrays of pointers to children and/or lines,
( Using B, P, E, and Inc() described recently:
_J************************@NCPlus.NET )...

...I just free one or more pointers and then
use memmove to overwrite them, the I adjust P,
e.g. -- Ln.P, or -- Forest.P .
( I would show you exactly how I do that,
but it's past 6 am now,
and I usually go to bed at 3 am,
and I have to be on campus by 10 am... uuugh ! )

You wrote: <<
Dereferencing a non-end pointer ( '*it' )
will get the item back. >>

Yea, that's similar to my code here:
LoopC ( & Flat )
if ( Eq ( Par, ( * Arr )->Ln [ _MID ] ) ) break ;
You showed:
collection.erase( collection.begin(), collection.end() );
saying: << If one wants an explicit forest of items
some work will be required to encapsulate them properly. >>

Right, the STL has no " Forest " type,
especially not one with unlimited children...

So your code above wouldn't work...
forests have to be recursively deleted/printed.

You said: " Enjoy your swamp muck... ".

Oh, of that you can be Quite sure...

I'm loving every minute of it.

But I've got to go now...
Jul 22 '05 #43

P: n/a
In message <sr*****************@newssvr15.news.prodigy.com> , Phlip
<ph*******@yahoo.com> writes
Jeff Relf wrote:
Hi Kelsey Bjarnason,

Re:
#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

You commented: << Marvellous; symbol clashes,
just because you use this macro twice in the same scope.
Talk about badly-written. >>

You're worried about compilation errors ?

Real programmers are Never concerned about that.


Real programmers don't piss their colleagues off. They write clear, simple,
robust, and easily-changed code. This helps keep their colleagues in the ...
loop.


They don't change the subject line with every reply, either.

--
Richard Herring
Jul 22 '05 #44

P: n/a
In comp.os.linux.advocacy, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid>
wrote
on 4 Aug 2004 13:26:28 GMT
<_J************************@NCPlus.NET>:
Hi The Ghost In The Machine,

You showed: <<
it = std::binary_search(
collection.begin(), collection.end(), "constant");

Yea, my original plan was to :

A. qsort() the unthread list of Usenet messages ( Flat ).
( Flat contains one huge array of pointers to nodes,
as described here
news:_J************************@NCPlus.NET )

B. Then do a binary search on it.

But then I ran the code... No need for the binary search.

It's already instant,

even with a list of two thousand messages.
( Even more so when compared to how long it takes me
to download those messages using a spotty dial-up service )

In fact, it's much much Much faster than 40Tude Dialog,
the newsreader that I was using before I wrote X.
( Actually, I'm still using Dialog for some things,
because X is still so primitive )

Re: Your code:
typedef std::string itemtype; // or whatever you want
typedef std::xxx<itemtype> collectiontype;
// xxx = set, vector, or list
collectiontype collection;
collectiontype::const_iterator it;

You said: " ...it should be fairly clear what I'm doing. "

Yes, it is quite clear ( and quite interesting too ).

You showed: <<
Now, after one's assigned a value to 'it',
one can then test 'it':

if ( it != collection.end() ) /* found it */

Of course, I do that all the time...

Only I say this: if ( J < LLL ) // found, i.e. broke out.

after: Loop( 5 ) if ( Eq( "Hello", Line_Array[ J ] ) ) break;

where: #define Eq ! strcmp


*hack* *cough*

Try

if(Eq(1, 2))

and see how far you get. I'll be standing way over here...

#define Loop( N ) int J = -1, LLL = N ; while ( ++ J < LLL )

The main difference is that I'm using J, not " it ",
and LLL, not collection.end() .
Right. Now replace your list with a red-black tree.

Re: collection.erase( it );

With my dynamic arrays of pointers to children and/or lines,
( Using B, P, E, and Inc() described recently:
_J************************@NCPlus.NET )...

...I just free one or more pointers and then
use memmove to overwrite them, the I adjust P,
e.g. -- Ln.P, or -- Forest.P .
( I would show you exactly how I do that,
but it's past 6 am now,
and I usually go to bed at 3 am,
and I have to be on campus by 10 am... uuugh ! )

You wrote: <<
Dereferencing a non-end pointer ( '*it' )
will get the item back. >>

Yea, that's similar to my code here:
LoopC ( & Flat )
if ( Eq ( Par, ( * Arr )->Ln [ _MID ] ) ) break ;
You showed:
collection.erase( collection.begin(), collection.end() );
saying: << If one wants an explicit forest of items
some work will be required to encapsulate them properly. >>

Right, the STL has no " Forest " type,
especially not one with unlimited children...
Don't be so sure. In fact, std::set<> and std::map<>
use a red-black tree.

You're right in that STL has no "Forest" type. I'm not sure
how much of a limitation that is.

So your code above wouldn't work...
forests have to be recursively deleted/printed.

You said: " Enjoy your swamp muck... ".

Oh, of that you can be Quite sure...

I'm loving every minute of it.

But I've got to go now...



--
#191, ew****@earthlink.net
It's still legal to go .sigless.
Jul 22 '05 #45

P: n/a
Hi Kelsey Bjarnason,

In news:_J************************@NCPlus.NET ,
I said to The Ghost: <<
...you and Kelsey Bjarnason were talking about
how much you dislike my AllocN() macro... >>

And you, not remembering what you last wrote, said: <<
Never mentioned it, AFAIK;
although I did make a mention or two about your
Loop and loop macros and your Zero macro. >>

To refresh your memory, see:
news:pa****************************@xxnospamyy.lig htspeed.bc.ca
( Shit, what a verbose Message-ID )

You quoted AllocN() and then commented: <<
Good god. If you're going to do that much work,
use a frippin' function, not a macro. >>

And I said that it was so I could do: { ... continue; }
thus creating fewer ( ugly ) braces in my code.

At any rate, I'm very glad you quoted AllocN(),
as that gave me an excuse to update it...
and to explain to you and the Ghost
how it creates a forest of bushy trees
( i.e. where the number of direct-children per node
is not limited ).

Re: memmove( Dest = malloc( Sz ), Source, Size )

You commented: << If malloc fails, you're hooped. >>

That wasn't my concern ( of course ),
I noticed that that code didn't work in certain places...

So I had to separate out the two calls, like this:
Dest = malloc( Sz ); memmove( Dest , Source, Size )

As I said... I have no idea why.

You quoted: P = ( Lnk_T ) malloc( sizeof NodeT );

And commented: << Okay, look, if you're coding in C,
lose the cast; it is extremely bad practice and hides bugs.
If you're coding in C++,
why are you using malloc at all, when there's new ? >>

I'm obviously coding in C++ ( only without the STL ),

You should've known that by all the binding I was doing,
eg: Line & Inc ( Ln_T & Ln );

So either you don't know C or you aren't reading my code...
Probably both. ( No big deal )

You asked why I use realloc() when there's new...

Compare new and realloc()... ( I'll wait )

Which is better ? ( No cheating )
Jul 22 '05 #46

P: n/a
Richard Herring,

Re: How I use appropriate titles, in compliance with RFC 1036.

RFC documents employ exact definitions of
these two all-uppercase words: SHOULD and MUST.

Because the title of a message SHOULD describe the message,
RFC 1036 says that when the topic changes:

A. One SHOULD Not use "Re: " at the start of a title.

B. One SHOULD Not delete the References line.

From http://www.usenet-fr.net/fr-chartes/...rfc1036.2.html
<< If the poster determines that
the topic of the followup differs significantly
from what is described in the subject,
a new, more descriptive, subject SHOULD be substituted
( With No Back Reference ). >>
^^^^ ^^ ^^^^ ^^^^^^^^^

The term, " back reference " here is defined as
the " Re: " tag at the start of a title,
( Not the References: line in the headers ).

Google violates RFC 1036 by mandating something more like this:

Because the title of a message MUST define the thread,
One MUST use "Re: " at the start of a title...
Otherwise we MUST delete the References line.

If you were to not side with Google's violation of RFC 1036...

You could " Sort by Thread " ( i.e. the references line ),
( rather than by titles ).

You also might consider unchecking the box that says:
" Start a new thread when the title changes ".

If you simply don't like RFC 1036,
and you choose to violate it...

Please don't complain to me
about the problems it is causing _ You _ .
Jul 22 '05 #47

P: n/a
On 31 Jul 2004 08:32:10 GMT, Jeff Relf
<Jeff_Relf_@_NCPlus.NET.Invalid> wrote:
You will never ever catch me telling someone that
his code is hard to maintain ( at least if I'm honest ).
You haven't been around much, have you.
I might well refuse to maintain someone's old code,
as I always prefer total rewrites.
You obviously have never spent a single minute in a commercial
software company, have you. Total rewrites... bwhaahaaaa.
I actually own a 450 dollar copy of MS Fortran for Win98.
( From when I converted some Fortran code to C )
But I never used it, thank God... I refused to.
So you converted from a language you never read about... okay, there's
a clue.
So I know what Fortran code ( and Fortran programmers )
look like ( with their big iron, IBM, and all that ).
But you said you never looked at the book?
I've seen those huge hard disk platters.
Did this excite you in some way?
Hmm... Where they the forerunner to floppies ?
( Not counting tape, of course )


"Never try to teach a pig to sing, it wastes time and annoys the pig."

Jul 22 '05 #48

This discussion thread is closed

Replies have been disabled for this discussion.