Sunday, June 30, 2019

Digest for comp.lang.c++@googlegroups.com - 19 updates in 7 topics

G G <gdotone@gmail.com>: Jun 30 04:16PM -0700

casting:
 
double ( a_value ) or (double) a_value
 
vs.
 
static_cast<double>( a_value ) /* c++ 11 + */
Horizon68 <horizon@horizon.com>: Jun 30 01:26PM -0700

Hello,
 
Read this:
 
 
Read again, i correct a typo because i write fast...
 
More about computing and parallel computing..
 
The important guaranties of Memory Safety in Rust are:
 
1- No Null Pointer Dereferences
2- No Dangling Pointers
3- No Buffer Overruns
 
I think i have solved Null Pointer Dereferences and also solved Dangling
Pointers and also solved memory leaks for Delphi and Freepascal by
inventing my "scalable" reference counting with efficient support for
weak references and i have implemented it in Delphi and Freepascal, and
reference counting in Rust and C++ is "not" scalable.
 
About the (3) above that is Buffer Overruns, read here about Delphi
and Freepascal:
 
What's a buffer overflow and how to avoid it in Delphi?
 
http://delphi.cjcsoft.net/viewthread.php?tid=49495
 
 
About Deadlock and Race conditions in Delphi and Freepascal:
 
I have ported DelphiConcurrent to Freepascal, and i have
also extended them with the support of my scalable RWLocks for Windows
and Linux and with the support of my scalable lock called MLock for
Windows and Linux and i have also added the support for a Mutex for
Windows and Linux, please look inside the DelphiConcurrent.pas and
FreepascalConcurrent.pas files inside the zip file to understand more.
 
You can download DelphiConcurrent and FreepascalConcurrent for Delphi
and Freepascal from:
 
https://sites.google.com/site/scalable68/delphiconcurrent-and-freepascalconcurrent
 
DelphiConcurrent and FreepascalConcurrent by Moualek Adlene is a new way
to build Delphi applications which involve parallel executed code based
on threads like application servers. DelphiConcurrent provides to the
programmers the internal mechanisms to write safer multi-thread code
while taking a special care of performance and genericity.
 
In concurrent applications a DEADLOCK may occurs when two threads or
more try to lock two consecutive shared resources or more but in a
different order. With DelphiConcurrent and FreepascalConcurrent, a
DEADLOCK is detected and automatically skipped - before he occurs - and
the programmer has an explicit exception describing the multi-thread
problem instead of a blocking DEADLOCK which freeze the application with
no output log (and perhaps also the linked clients sessions if we talk
about an application server).
 
Amine Moulay Ramdane has extended them with the support of his scalable
RWLocks for Windows and Linux and with the support of his scalable lock
called MLock for Windows and Linux and he has also added the support for
a Mutex for Windows and Linux, please look inside the
DelphiConcurrent.pas and FreepascalConcurrent.pas files to understand more.
 
And please read the html file inside to learn more how to use it.
 
 
About race conditions now:
 
My scalable Adder is here..
 
As you have noticed i have just posted previously my modified versions
of DelphiConcurrent and FreepascalConcurrent to deal with deadlocks in
parallel programs.
 
But i have just read the following about how to avoid race conditions in
Parallel programming in most cases..
 
Here it is:
 
https://vitaliburkov.wordpress.com/2011/10/28/parallel-programming-with-delphi-part-ii-resolving-race-conditions/
 
This is why i have invented my following powerful scalable Adder to help
you do the same as the above, please take a look at its source code to
understand more, here it is:
 
https://sites.google.com/site/scalable68/scalable-adder-for-delphi-and-freepascal
 
Other than that, about composability of lock-based systems now:
 
Design your systems to be composable. Among the more galling claims of
the detractors of lock-based systems is the notion that they are somehow
uncomposable: "Locks and condition variables do not support modular
programming," reads one typically brazen claim, "building large programs
by gluing together smaller programs[:] locks make this impossible."9 The
claim, of course, is incorrect. For evidence one need only point at the
composition of lock-based systems such as databases and operating
systems into larger systems that remain entirely unaware of lower-level
locking.
 
There are two ways to make lock-based systems completely composable, and
each has its own place. First (and most obviously), one can make locking
entirely internal to the subsystem. For example, in concurrent operating
systems, control never returns to user level with in-kernel locks held;
the locks used to implement the system itself are entirely behind the
system call interface that constitutes the interface to the system. More
generally, this model can work whenever a crisp interface exists between
software components: as long as control flow is never returned to the
caller with locks held, the subsystem will remain composable.
 
Second (and perhaps counterintuitively), one can achieve concurrency and
composability by having no locks whatsoever. In this case, there must be
no global subsystem state—subsystem state must be captured in
per-instance state, and it must be up to consumers of the subsystem to
assure that they do not access their instance in parallel. By leaving
locking up to the client of the subsystem, the subsystem itself can be
used concurrently by different subsystems and in different contexts. A
concrete example of this is the AVL tree implementation used extensively
in the Solaris kernel. As with any balanced binary tree, the
implementation is sufficiently complex to merit componentization, but by
not having any global state, the implementation may be used concurrently
by disjoint subsystems—the only constraint is that manipulation of a
single AVL tree instance must be serialized.
 
Read more here:
 
https://queue.acm.org/detail.cfm?id=1454462
 
And about Message Passing Process Communication Model and Shared Memory
Process Communication Model:
 
An advantage of shared memory model is that memory communication is
faster as compared to the message passing model on the same machine.
 
However, shared memory model may create problems such as synchronization
and memory protection that need to be addressed.
 
Message passing's major flaw is the inversion of control–it is a moral
equivalent of gotos in un-structured programming (it's about time
somebody said that message passing is considered harmful).
 
Also some research shows that the total effort to write an MPI
application is significantly higher than that required to write a
shared-memory version of it.
 
And more about my scalable reference counting with efficient support
for weak references:
 
My invention that is my scalable reference counting with efficient
support for weak references version 1.35 is here..
 
Here i am again, i have just updated my scalable reference counting with
efficient support for weak references to version 1.35, I have just added
a TAMInterfacedPersistent that is a scalable reference counted version,
and now i think i have just made it complete and powerful.
 
Because I have just read the following web page:
 
https://www.codeproject.com/Articles/1252175/Fixing-Delphis-Interface-Limitations
 
But i don't agree with the writting of the guy of the above web page,
because i think you have to understand the "spirit" of Delphi, here is why:
 
A component is supposed to be owned and destroyed by something else,
"typically" a form (and "typically" means in english: in "most" cases,
and this is the most important thing to understand). In that scenario,
reference count is not used.
 
If you pass a component as an interface reference, it would be very
unfortunate if it was destroyed when the method returns.
 
Therefore, reference counting in TComponent has been removed.
 
Also because i have just added TAMInterfacedPersistent to my invention.
 
To use scalable reference counting with Delphi and FreePascal, just
replace TInterfacedObject with my TAMInterfacedObject that is the
scalable reference counted version, and just replace
TInterfacedPersistent with my TAMInterfacedPersistent that is the
scalable reference counted version, and you will find both my
TAMInterfacedObject and my TAMInterfacedPersistent inside the
AMInterfacedObject.pas file, and to know how to use weak references
please take a look at the demo that i have included called example.dpr
and look inside my zip file at the tutorial about weak references, and
to know how to use delegation take a look at the demo that i have
included called test_delegation.pas, and take a look inside my zip file
at the tutorial about delegation that learns you how to use delegation.
 
I think my Scalable reference counting with efficient support for weak
references is stable and fast, and it works on both Windows and Linux,
and my scalable reference counting scales on multicore and NUMA systems,
and you will not find it in C++ or Rust, and i don't think you will find
it anywhere, and you have to know that this invention of mine solves
the problem of dangling pointers and it solves the problem of memory
leaks and my scalable reference counting is "scalable".
 
And please read the readme file inside the zip file that i have just
extended to make you understand more.
 
You can download my new scalable reference counting with efficient
support for weak references version 1.35 from:
 
https://sites.google.com/site/scalable68/scalable-reference-counting-with-efficient-support-for-weak-references
 
 
Thank you,
Amine Moulay Ramdane.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 30 10:09PM +0100

On 30/06/2019 21:26, Horizon68 wrote:
> Hello,
 
> Read this:
 
> Read again, i correct a typo because i write fast...
 
Why would we read it again you demented loon?
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into
snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Jorgen Grahn <grahn+nntp@snipabacken.se>: Jun 30 05:58AM

On Sat, 2019-06-29, G G wrote:
 
[Attribution missing; I think David Brown wrote this]
 
> the code. But to ensure I'm not taking undue credit, the code is from a CERT
> website, www.securecoding.cert.org from a search INT32-CPP.
> At that site, they show many other concerns and suggestions how to mitigate.
 
I'm sure his advice was for you, me, and everyone, including the CERT
people. There are different schools of thought here, and has been for
as long as I can remember.
 
BTW, the code left out the most interesting part. It said:
 
/* Handle error */
 
If aborting isn't an option, it's really hard to fill in that part of
the function, and it's often impossible to get test coverage for it
in a full system test.
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
G G <gdotone@gmail.com>: Jun 30 02:43AM -0700


> I'm sure his advice was for you, me, and everyone, including the CERT
> people.
 
I'm sure too.
I thank him, you, and everyone who helps me learn.
"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>: Jun 30 03:00AM -0700

On 6/28/2019 7:46 PM, G G wrote:
 
> are these checks still necessary or is there another way?
[...]
 
Its been a while since I read the following, cannot remember if it goes
into overflows:
 
http://www.stroustrup.com/JSF-AV-rules.pdf
"Öö Tiib" <ootiib@hot.ee>: Jun 30 07:19AM -0700

On Saturday, 29 June 2019 05:46:54 UTC+3, G G wrote:
> are these checks still necessary or is there another way?
 
> https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow
 
Yes, quarter of possible signed addition or subtraction
operations are undefined behavior by standard.
 
There may be are non-standard compiler intrinsics that
help us to deal with overflows more simply or we can use
a type for result where every resulting value fits.
 
For example we can detect if distance between every two
signed longs fits into unsigned long with a compile-time
check:
 
static_assert(ULONG_MAX/2 >= LONG_MAX);
 
So we can luckily write a distance function that can never
fail if it compiles:
 
#include <iostream>
#include <limits.h>
 
unsigned long distance(long x, long y)
{
static_assert(ULONG_MAX/2 >= LONG_MAX);
return (x > y) ? (unsigned long)x - (unsigned long)y
: (unsigned long)y - (unsigned long)x;
}
 
int main()
{
std::cout << "Distance between 3 and -42 is "
<< distance(3, -42) << std::endl;
}
 
I prefer to use int64_t and uint64_t that guarantee that
UINT64_MAX/2 >= INT64_MAX so I don't need that
static_assert.

However quite common is that meaningful limits for a
number are rather different from what the integer type
of processor has.
 
For example we need to have variable that represents
reasonably reachable temperatures with accuracy of
one centi degree of Celsius.
 
The int32_t that we might want to use has range
-2147483648 to 2147483647 so most of that range will
be erroneous values.
 
Absolute zero is −273.15°C, can't go below that.
Temperatures within stars can reach millions of degrees
(thanks to pressure) but at surface of Sun we have "only"
5505°C. Therefore we should check limits like
-27315 to 600000 (far under INT32_MIN and INT32_MAX)
to figure if our values are outside of sanity limits or not.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 30 04:44PM +0200

On 30.06.2019 16:19, Öö Tiib wrote:
> signed longs fits into unsigned long with a compile-time
> check:
 
> static_assert(ULONG_MAX/2 >= LONG_MAX);
 
Will always be true for two's complement form, by definition. floor(
(2^n)-1)/2 ) = floor( 2^(n-1) - 1/2 ) = 2^(n-1)-1, which is LONG_MAX.
 
 
> return (x > y) ? (unsigned long)x - (unsigned long)y
> : (unsigned long)y - (unsigned long)x;
> }
 
Yes, but the assertion isn't necessary. ;-)
 
The distance between two numbers in a 2^n range can never be 2^n or higher.
 
 
> 5505°C. Therefore we should check limits like
> -27315 to 600000 (far under INT32_MIN and INT32_MAX)
> to figure if our values are outside of sanity limits or not.
 
And always think of Ariane 5.
 
 
Cheers!,
 
- Alf
"Öö Tiib" <ootiib@hot.ee>: Jun 30 08:18AM -0700

On Sunday, 30 June 2019 17:44:53 UTC+3, Alf P. Steinbach wrote:
 
> > static_assert(ULONG_MAX/2 >= LONG_MAX);
 
> Will always be true for two's complement form, by definition. floor(
> (2^n)-1)/2 ) = floor( 2^(n-1) - 1/2 ) = 2^(n-1)-1, which is LONG_MAX.
 
Yes but two's complement is not guaranteed for long.
Basically if we assume two's complement then we better
use types that guarantee it like I said later:

> > UINT64_MAX/2 >= INT64_MAX so I don't need that
> > static_assert.
 
> And always think of Ariane 5.
 
You mean partially failed launch 25 January 2018? I
wasn't involved. :D Incorrect value in specifications.
That is hard to avoid in practice because infallible and
omnipotent humans are impossible to hire for whatever
money.
 
For example if to take and to let three separate teams to
write same software and then let the resulting programs to
vote each decision ... if the specs were defective then
these would likely suggest same, incorrect decision
unanimously.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 30 06:22PM +0200

On 30.06.2019 17:18, Öö Tiib wrote:
 
>> Will always be true for two's complement form, by definition. floor(
>> (2^n)-1)/2 ) = floor( 2^(n-1) - 1/2 ) = 2^(n-1)-1, which is LONG_MAX.
 
> Yes but two's complement is not guaranteed for long.
 
Oh it is.
 
No extant compiler uses anything else, and next year you get it
guaranteed from the standard too.
 
 
> vote each decision ... if the specs were defective then
> these would likely suggest same, incorrect decision
> unanimously.
 
Cheers!
 
- Alf
David Brown <david.brown@hesbynett.no>: Jun 30 10:22PM +0200

On 30/06/2019 01:02, G G wrote:
> the code. But to ensure I'm not taking undue credit, the code is from a CERT
> website, www.securecoding.cert.org from a search INT32-CPP.
> At that site, they show many other concerns and suggestions how to mitigate.
 
Yes, I meant "you" in general, not just you personally.
 
I've seen that page. The sample code is silly and pointless, because it
solves a problem that doesn't exist while failing to address the problem
that /does/ exist.
 
Overflows (including unsigned overflows, which are also usually errors)
occur because people don't do a good enough job of checking data coming
in from outside, and don't check that their calculations will work over
the full range of the data they are using. Checking specifically over
the range of "int" is pointless.
David Brown <david.brown@hesbynett.no>: Jun 30 10:24PM +0200

On 30/06/2019 11:43, G G wrote:
>> people.
 
> I'm sure too.
> I thank him, you, and everyone who helps me learn.
 
(/Please/ use appropriate attributions. Even if you have to use the
appalling google groups interface instead of a proper newsreader and
newsserver, you should make the effort to keep attributions.)
David Brown <david.brown@hesbynett.no>: Jun 30 10:25PM +0200

On 30/06/2019 07:58, Jorgen Grahn wrote:
> the function, and it's often impossible to get test coverage for it
> in a full system test.NoNoNo
 
> /Jorgen
 
That is a very important point - thanks for bringing it up. You (yous,
or y'all) should not include code that can't be tested.
Horizon68 <horizon@horizon.com>: Jun 30 12:05PM -0700

Hello..
 
 
More about computing and parallel computing..
 
The important guaranties of Memory Safety in Rust are:
 
1- No Null Pointer Dereferences
2- No Dangling Pointers
3- No Buffer Overruns
 
I think i have solved Pointer Dereferences and also solved Dangling
Pointers and also solved memory leaks for Delphi and Freepascal by
inventing my "scalable" reference counting with efficient support for
weak references and i have implemented it in Delphi and Freepascal, and
reference counting in Rust and C++ is "not" scalable.
 
About the (3) above that is Buffer Overruns, read here about Delphi
and Freepascal:
 
What's a buffer overflow and how to avoid it in Delphi?
 
http://delphi.cjcsoft.net/viewthread.php?tid=49495
 
 
About Deadlock and Race conditions in Delphi and Freepascal:
 
I have ported DelphiConcurrent to Freepascal, and i have
also extended them with the support of my scalable RWLocks for Windows
and Linux and with the support of my scalable lock called MLock for
Windows and Linux and i have also added the support for a Mutex for
Windows and Linux, please look inside the DelphiConcurrent.pas and
FreepascalConcurrent.pas files inside the zip file to understand more.
 
You can download DelphiConcurrent and FreepascalConcurrent for Delphi
and Freepascal from:
 
https://sites.google.com/site/scalable68/delphiconcurrent-and-freepascalconcurrent
 
DelphiConcurrent and FreepascalConcurrent by Moualek Adlene is a new way
to build Delphi applications which involve parallel executed code based
on threads like application servers. DelphiConcurrent provides to the
programmers the internal mechanisms to write safer multi-thread code
while taking a special care of performance and genericity.
 
In concurrent applications a DEADLOCK may occurs when two threads or
more try to lock two consecutive shared resources or more but in a
different order. With DelphiConcurrent and FreepascalConcurrent, a
DEADLOCK is detected and automatically skipped - before he occurs - and
the programmer has an explicit exception describing the multi-thread
problem instead of a blocking DEADLOCK which freeze the application with
no output log (and perhaps also the linked clients sessions if we talk
about an application server).
 
Amine Moulay Ramdane has extended them with the support of his scalable
RWLocks for Windows and Linux and with the support of his scalable lock
called MLock for Windows and Linux and he has also added the support for
a Mutex for Windows and Linux, please look inside the
DelphiConcurrent.pas and FreepascalConcurrent.pas files to understand more.
 
And please read the html file inside to learn more how to use it.
 
 
About race conditions now:
 
My scalable Adder is here..
 
As you have noticed i have just posted previously my modified versions
of DelphiConcurrent and FreepascalConcurrent to deal with deadlocks in
parallel programs.
 
But i have just read the following about how to avoid race conditions in
Parallel programming in most cases..
 
Here it is:
 
https://vitaliburkov.wordpress.com/2011/10/28/parallel-programming-with-delphi-part-ii-resolving-race-conditions/
 
This is why i have invented my following powerful scalable Adder to help
you do the same as the above, please take a look at its source code to
understand more, here it is:
 
https://sites.google.com/site/scalable68/scalable-adder-for-delphi-and-freepascal
 
Other than that, about composability of lock-based systems now:
 
Design your systems to be composable. Among the more galling claims of
the detractors of lock-based systems is the notion that they are somehow
uncomposable: "Locks and condition variables do not support modular
programming," reads one typically brazen claim, "building large programs
by gluing together smaller programs[:] locks make this impossible."9 The
claim, of course, is incorrect. For evidence one need only point at the
composition of lock-based systems such as databases and operating
systems into larger systems that remain entirely unaware of lower-level
locking.
 
There are two ways to make lock-based systems completely composable, and
each has its own place. First (and most obviously), one can make locking
entirely internal to the subsystem. For example, in concurrent operating
systems, control never returns to user level with in-kernel locks held;
the locks used to implement the system itself are entirely behind the
system call interface that constitutes the interface to the system. More
generally, this model can work whenever a crisp interface exists between
software components: as long as control flow is never returned to the
caller with locks held, the subsystem will remain composable.
 
Second (and perhaps counterintuitively), one can achieve concurrency and
composability by having no locks whatsoever. In this case, there must be
no global subsystem state—subsystem state must be captured in
per-instance state, and it must be up to consumers of the subsystem to
assure that they do not access their instance in parallel. By leaving
locking up to the client of the subsystem, the subsystem itself can be
used concurrently by different subsystems and in different contexts. A
concrete example of this is the AVL tree implementation used extensively
in the Solaris kernel. As with any balanced binary tree, the
implementation is sufficiently complex to merit componentization, but by
not having any global state, the implementation may be used concurrently
by disjoint subsystems—the only constraint is that manipulation of a
single AVL tree instance must be serialized.
 
Read more here:
 
https://queue.acm.org/detail.cfm?id=1454462
 
And about Message Passing Process Communication Model and Shared Memory
Process Communication Model:
 
An advantage of shared memory model is that memory communication is
faster as compared to the message passing model on the same machine.
 
However, shared memory model may create problems such as synchronization
and memory protection that need to be addressed.
 
Message passing's major flaw is the inversion of control–it is a moral
equivalent of gotos in un-structured programming (it's about time
somebody said that message passing is considered harmful).
 
Also some research shows that the total effort to write an MPI
application is significantly higher than that required to write a
shared-memory version of it.
 
And more about my scalable reference counting with efficient support
for weak references:
 
My invention that is my scalable reference counting with efficient
support for weak references version 1.35 is here..
 
Here i am again, i have just updated my scalable reference counting with
efficient support for weak references to version 1.35, I have just added
a TAMInterfacedPersistent that is a scalable reference counted version,
and now i think i have just made it complete and powerful.
 
Because I have just read the following web page:
 
https://www.codeproject.com/Articles/1252175/Fixing-Delphis-Interface-Limitations
 
But i don't agree with the writting of the guy of the above web page,
because i think you have to understand the "spirit" of Delphi, here is why:
 
A component is supposed to be owned and destroyed by something else,
"typically" a form (and "typically" means in english: in "most" cases,
and this is the most important thing to understand). In that scenario,
reference count is not used.
 
If you pass a component as an interface reference, it would be very
unfortunate if it was destroyed when the method returns.
 
Therefore, reference counting in TComponent has been removed.
 
Also because i have just added TAMInterfacedPersistent to my invention.
 
To use scalable reference counting with Delphi and FreePascal, just
replace TInterfacedObject with my TAMInterfacedObject that is the
scalable reference counted version, and just replace
TInterfacedPersistent with my TAMInterfacedPersistent that is the
scalable reference counted version, and you will find both my
TAMInterfacedObject and my TAMInterfacedPersistent inside the
AMInterfacedObject.pas file, and to know how to use weak references
please take a look at the demo that i have included called example.dpr
and look inside my zip file at the tutorial about weak references, and
to know how to use delegation take a look at the demo that i have
included called test_delegation.pas, and take a look inside my zip file
at the tutorial about delegation that learns you how to use delegation.
 
I think my Scalable reference counting with efficient support for weak
references is stable and fast, and it works on both Windows and Linux,
and my scalable reference counting scales on multicore and NUMA systems,
and you will not find it in C++ or Rust, and i don't think you will find
it anywhere, and you have to know that this invention of mine solves
the problem of dangling pointers and it solves the problem of memory
leaks and my scalable reference counting is "scalable".
 
And please read the readme file inside the zip file that i have just
extended to make you understand more.
 
You can download my new scalable reference counting with efficient
support for weak references version 1.35 from:
 
https://sites.google.com/site/scalable68/scalable-reference-counting-with-efficient-support-for-weak-references
 
 
Thank you,
Amine Moulay Ramdane.
alexo <alelvb@inwind.it>: Jun 30 06:43PM +0200

Il 30/06/19 16:04, Stefan Ram ha scritto:
 
Hi Stefan, your parser works correctly. I checked with other formulas
{'such as
 
[Fe(CO)6][Sb2F11]2
 
1 * [ 1 * Fe + 6 * ( 1 * C + 1 * O ) ] + 2 * [ 2 * Sb + 11 * F ]
 
and
 
HRh(CO)[P[CH2CH2(CF2)5CF]3]3
 
for which the output is:
 
1 * H + 1 * Rh + 1 * ( 1 * C + 1 * O ) + 3 * [ 1 * P + 3 * [ 1 * C + 2 *
H + 1 * C + 2 * H + 5 * ( 1 * C + 2 * F ) + 1 * C + 1 * F ] ]
 
 
To say it all, the text from which I took this formula reports it as:
 
HRh(CO)[P{CH2CH2(CF2)5CF}3]3
 
i.e with another kind of parentheses '{' and '}
 
I added that to your parser.
You did a great job.
 
But to be perfect it should handle even the molecules of crystallization
that are written in this way (but I didn't talk about them in my post:
 
 
CuSO4*5H2O
 
here there are 5 molecules of H2O in the composition of the molecule.
The '*' character is the one I use because it should be used the
'central dot' character but I don't know how to type it.
 
 
 
here is your program purged by all those ::std that made the text hard
to read:
 
 
#include <cctype>
#include <iostream>
#include <istream>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
 
using namespace ::std::literals;
 
using std::string;
using std::move;
using std::cout;
using std::istringstream;
 
template< typename source >struct scanner
{ source s;
 
string peek_value;
 
typename source::int_type eof { source::traits_type::eof() };
 
scanner( source && s )noexcept : s{ move( s )}, peek_value{ ""s } {}
 
scanner( scanner && s )noexcept : s{ static_cast<source&&>(s.s)},
peek_value{static_cast<string&&>(s.peek_value)} { }
 
string name( char c )
{ string result;
if( isalpha( c ))
{ int pos {};
while( isalpha( c )&&( pos == 0 || islower( c )))
{ pos = 1;
c = static_cast< char >( s.get() );
result += c;
auto const i = s.peek();
if( i == eof )return result;
c = static_cast< char >( i ); }}
return result; }
 
string number( char c )
{ string result;
if( isdigit( c ))
{ while( isdigit( c ))
{ c = static_cast< char >( s.get() );
result += c;
auto const i = s.peek();
if( i == eof )return result;
c = static_cast< char >( i ); }}
return result; }
 
string special( char c )
{ string result;
if( c == '(' || c == ')' || c == '[' || c == ']' || c == '{' || c
== '}')
{ c = static_cast< char >( s.get() );
result += c;
return result; }
return result; }
 
string do_get()
{ string result;
auto const i = s.peek();
if( i == eof )return result;
else
{ auto c { static_cast< char >( i )};
result = name( c ); if( result != ""s )return result;
result = number( c ); if( result != ""s )return result;
result = special( c ); if( result != ""s )return result;
return result; }
return result; }
 
string get()
{ if( peek_value != ""s )
{ string const result{ peek_value };
peek_value = ""s;
return result; }
else return do_get(); }
 
string peek()
{ if( peek_value == ""s )peek_value = do_get();
return peek_value; }};
 
 
struct parse_type
{ virtual string surface() const = 0;
virtual string description() const = 0;
parse_type()= default;
parse_type( const parse_type & )= default;
parse_type( parse_type && )= default;
parse_type & operator=( const parse_type & )= default;
parse_type & operator=( parse_type && )noexcept = default;
virtual ~parse_type() = default; };
 
struct primary_parse_type final : public parse_type
{ parse_type const * primary;
primary_parse_type( const primary_parse_type & )= default;
primary_parse_type& operator=(const primary_parse_type&)= default;
primary_parse_type( parse_type const * primary ):
primary{ primary } {}
string surface() const override { return primary->surface(); }
string description() const override
{ return primary->description(); }};
 
struct name_parse_type;
 
struct name_parse_type final : public parse_type
{ string surface_;
name_parse_type( string surface ):surface_{ move(surface) } {}
string surface() const override { return surface_; }
string description() const override { return surface_; }};
 
struct number_parse_type final : public parse_type
{ string surface_;
number_parse_type( string surface ):surface_{ move(surface) } {}
string surface() const override { return surface_; }
string description() const override { return "number "s + surface_; }};
 
struct product_parse_type final : public parse_type
{ string surface_;
primary_parse_type * component;
string multiplicity;
product_parse_type(const product_parse_type&)=default;
product_parse_type& operator=(const product_parse_type&)=default;
product_parse_type( string surface, primary_parse_type * component,
string multiplicity ):
surface_{ move(surface) }, component{ component }, multiplicity{
move(multiplicity) } {}
string surface() const override { return surface_; }
string description() const override { return multiplicity + " * " +
component->description(); }};
 
struct sum_parse_type final : public parse_type
{ string surface_;
::std::vector< product_parse_type >vector;
sum_parse_type( string surface, ::std::vector< product_parse_type >
vector ):
surface_{ move(surface) }, vector{ move(vector) } {}
string const plus = " + "s;
void append_surface( string const & s ){ surface_ += s; }
void append_addend( product_parse_type const & s ){ vector.push_back(
s ); }
string surface() const override { return surface_; }
string description() const override
{ string result;
bool first = true;
for( auto & entry: vector )
if( first ){ result = entry.description(); first = false; }
else result = result + plus + entry.description();
return result; }};
 
struct paren_parse_type final : public parse_type
{ string surface_;
string lpar;
string rpar;
sum_parse_type sum;
paren_parse_type( string surface, string lpar, string rpar,
sum_parse_type sum ):
surface_{ move(surface) }, lpar{ move(lpar) }, rpar{ move(rpar) },
sum{ move(sum) } {}
string const space{ " "s };
string surface() const override { return surface_; }
string description() const override
{ return lpar + space + sum.description() + space + rpar; }};
 
 
template< typename scanner >struct parser_type
{ scanner sc;
explicit parser_type( scanner && sc ): sc{ move( sc )} {}
 
name_parse_type get_name()
{ string t;
t = sc.get(); return name_parse_type{ t }; }
 
number_parse_type get_number()
{ string t; t = sc.get(); return number_parse_type{ t }; }
 
product_parse_type get_product()
{ primary_parse_type const component { get_primary() };
string preview { sc.peek() };
bool const is_product { preview.length() > 0 && isdigit(
preview.at( 0 )) };
string const multiplicity { is_product ? sc.get(): "1"s };
return product_parse_type{ component.surface() +( is_product ?
preview : ""s ), new primary_parse_type { component }, multiplicity }; }
 
sum_parse_type get_sum()
{ auto result { sum_parse_type{ ""s, {} }};
product_parse_type component { get_product() };
if( component.surface() == ""s )return result;
result.append_surface( component.surface() );
result.append_addend( component );
string preview;
while( true )
{ preview = sc.peek();
bool const is_sum { preview.length() > 0 &&( isalpha(
preview.front() ) || preview.front() == '(' || preview.front() == '[' ||
preview.front() == '{') };
if( !is_sum )return result;
component = get_product();
result.append_surface( component.surface() );
result.append_addend( component ); }
return sum_parse_type{ ""s, {} }; }
 
paren_parse_type get_paren()
{ string const lpar { sc.get() };
sum_parse_type const sum { get_sum() };
string const rpar { sc.get() };
return paren_parse_type
{ lpar + sum.surface() + rpar, lpar, rpar, sum }; }
 
primary_parse_type get_primary()
{ auto next { sc.peek() };
if( isalpha( next.front() ))
{ name_parse_type name = get_name();
return new name_parse_type{ name }; }
if( next.front() == '(' || next.front() == '[' || next.front() == '{')
{ paren_parse_type paren = get_paren();
return new paren_parse_type{ paren }; }
return nullptr; }};
 
int main()
{ istringstream s{ "HRh(CO)[P{CH2CH2(CF2)5CF}3]3" };
scanner< istringstream >sc{ move( s )};
parser_type< scanner< istringstream > >parser{ move( sc )};
sum_parse_type sum_value = parser.get_sum();
cout << sum_value.surface() << '\n';
cout << sum_value.description() << '\n'; }
"Heinz Müller" <Heinz.Mueller69@gmail.com>: Jun 30 07:07PM +0200

> sum_parse_type sum_value = parser.get_sum();
> ::std::cout << sum_value.surface() << '\n';
> ::std::cout << sum_value.description() << '\n'; }
 
You've won the 2019 obfuscated code contest!
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jun 30 07:54PM +0100

On 30/06/2019 15:04, Stefan Ram wrote:
> sum_parse_type sum_value = parser.get_sum();
> ::std::cout << sum_value.surface() << '\n';
> ::std::cout << sum_value.description() << '\n'; }
 
What's with all the `::std::`? `std::` is fine. Your code is nearly as
bad as Alf's.
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into
snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who
doesn't believe in any God the most. Oh, no..wait.. that never happens." –
Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
"Öö Tiib" <ootiib@hot.ee>: Jun 30 09:16AM -0700

On Friday, 28 June 2019 09:24:00 UTC+3, Tim Rentsch wrote:
 
> (Direct is not the same as short here. My viewpoint has more
> than a few different aspects, which is to say too many to be
> conveyed in only one or two sentences, so please be thorough.)
 
My impression, (but I may be wrong there) is that you consider
"undefined behavior" to be synonymous with "behavior caused
by programming error". For me these two things overlap a lot
but also have differences. Some clear constraint violations
result with defined behavior but some flawless programs
may end with undefined behavior.
 
For some of those situations we have signals like SIGILL
and SIGSEGV. There are no defined behaviors that cause
those.
 
In running system it is impossible to figure if these signals
were caused by programming error in some program, defect
in hardware, defect in compiler, defect in operating system,
misconfiguration of any of those, external attackers or cosmic
rays. So as a programmer of software it is not what I have
to deal with. Instead my software needs to give up any control
it has and to notify possible backup systems about it as fast
as possible.
 
Same with exceeding automatic storage limits. I would be lot
happier if C++ did provide me some runtime way to check
how lot of automatic storage is left or at least guarantee
that SIGSEGV when automatic storage is exhausted.
But unfortunately C++ neither provides nor guarantees
anything and so it is undefined behavior.
ram@zedat.fu-berlin.de (Stefan Ram): Jun 30 02:04PM

>but not the following:
>[Be(N(CH3)2)2]3
 
Here is a quick attempt to write a parser for it.
 
However, this is just a "quick and dirty" solution,
it is a first draft, a kind of "compilable pseudo code",
it contains some some unnecessary lines.
 
It can parse the above formula, but has not been
tested with other formulas, and it allocates memory
with "new" that never is freed (it is leaking memory).
 
Maybe better memory management can be achieved by
overwriting the destructors?
 
input (see "main"):
 
[Be(N(CH3)2)2]3
 
output (written to stdout):
 
3 * [ 1 * Be + 2 * ( 1 * N + 2 * ( 1 * C + 3 * H ) ) ]
 
source code (wide lines!):
 
#include <cctype>
#include <iostream>
#include <istream>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
#include <vector>
 
using namespace ::std::literals;
 
template< typename source >struct scanner
{ source s;
 
::std::string peek_value;
 
typename source::int_type eof { source::traits_type::eof() };
 
scanner( source && s )noexcept : s{ ::std::move( s )}, peek_value{ ""s } {}
 
scanner( scanner && s )noexcept : s{ static_cast<source&&>(s.s)}, peek_value{static_cast<::std::string&&>(s.peek_value)} { }
 
::std::string name( char c )
{ ::std::string result;
if( isalpha( c ))
{ int pos {};
while( isalpha( c )&&( pos == 0 || islower( c )))
{ pos = 1;
c = static_cast< char >( s.get() );
result += c;
auto const i = s.peek();
if( i == eof )return result;
c = static_cast< char >( i ); }}
return result; }
 
::std::string number( char c )
{ ::std::string result;
if( isdigit( c ))
{ while( isdigit( c ))
{ c = static_cast< char >( s.get() );
result += c;
auto const i = s.peek();
if( i == eof )return result;
c = static_cast< char >( i ); }}
return result; }
 
::std::string special( char c )
{ ::std::string result;
if( c == '(' || c == ')' || c == '[' || c == ']' )
{ c = static_cast< char >( s.get() );
result += c;
return result; }
return result; }
 
::std::string do_get()
{ ::std::string result;
auto const i = s.peek();
if( i == eof )return result;
else
{ auto c { static_cast< char >( i )};
result = name( c ); if( result != ""s )return result;
result = number( c ); if( result != ""s )return result;
result = special( c ); if( result != ""s )return result;
return result; }
return result; }
 
::std::string get()
{ if( peek_value != ""s )
{ ::std::string const result{ peek_value };
peek_value = ""s;
return result; }
else return do_get(); }
 
::std::string peek()
{ if( peek_value == ""s )peek_value = do_get();
return peek_value; }};
 
 
struct parse_type
{ virtual ::std::string surface() const = 0;
virtual ::std::string description() const = 0;
parse_type()= default;
parse_type( const parse_type & )= default;
parse_type( parse_type && )= default;
parse_type & operator=( const parse_type & )= default;
parse_type & operator=( parse_type && )noexcept = default;
virtual ~parse_type() = default; };
 
struct primary_parse_type final : public parse_type
{ parse_type const * primary;
primary_parse_type( const primary_parse_type & )= default;
primary_parse_type& operator=(const primary_parse_type&)= default;
primary_parse_type( parse_type const * primary ):
primary{ primary } {}
::std::string surface() const override { return primary->surface(); }
::std::string description() const override
{ return primary->description(); }};
 
struct name_parse_type;
 
struct name_parse_type final : public parse_type
{ ::std::string surface_;
name_parse_type( ::std::string surface ):surface_{ ::std::move(surface) } {}
::std::string surface() const override { return surface_; }
::std::string description() const override { return surface_; }};
 
struct number_parse_type final : public parse_type
{ ::std::string surface_;
number_parse_type( ::std::string surface ):surface_{ ::std::move(surface) } {}
::std::string surface() const override { return surface_; }
::std::string description() const override { return "number "s + surface_; }};
 
struct product_parse_type final : public parse_type
{ ::std::string surface_;
primary_parse_type * component;
::std::string multiplicity;
product_parse_type(const product_parse_type&)=default;
product_parse_type& operator=(const product_parse_type&)=default;
product_parse_type( ::std::string surface, primary_parse_type * component, ::std::string multiplicity ):
surface_{ ::std::move(surface) }, component{ component }, multiplicity{ ::std::move(multiplicity) } {}
::std::string surface() const override { return surface_; }
::std::string description() const override { return multiplicity + " * " + component->description(); }};
 
struct sum_parse_type final : public parse_type
{ ::std::string surface_;
::std::vector< product_parse_type >vector;
sum_parse_type( ::std::string surface, ::std::vector< product_parse_type > vector ):
surface_{ ::std::move(surface) }, vector{ ::std::move(vector) } {}
::std::string const plus = " + "s;
void append_surface( ::std::string const & s ){ surface_ += s; }
void append_addend( product_parse_type const & s ){ vector.push_back( s ); }
::std::string surface() const override { return surface_; }
::std::string description() const override
{ ::std::string result;
bool first = true;
for( auto & entry: vector )
if( first ){ result = entry.description(); first = false; }
else result = result + plus + entry.description();
return result; }};
 
struct paren_parse_type final : public parse_type
{ ::std::string surface_;
::std::string lpar;
::std::string rpar;
sum_parse_type sum;
paren_parse_type( ::std::string surface, ::std::string lpar, ::std::string rpar, sum_parse_type sum ):
surface_{ ::std::move(surface) }, lpar{ ::std::move(lpar) }, rpar{ ::std::move(rpar) }, sum{ ::std::move(sum) } {}
::std::string const space{ " "s };
::std::string surface() const override { return surface_; }
::std::string description() const override
{ return lpar + space + sum.description() + space + rpar; }};
 
 
template< typename scanner >struct parser_type
{ scanner sc;
explicit parser_type( scanner && sc ): sc{ ::std::move( sc )} {}
 
name_parse_type get_name()
{ ::std::string t;
t = sc.get(); return name_parse_type{ t }; }
 
number_parse_type get_number()
{ ::std::string t; t = sc.get(); return number_parse_type{ t }; }
 
product_parse_type get_product()
{ primary_parse_type const component { get_primary() };
::std::string preview { sc.peek() };
bool const is_product { preview.length() > 0 && isdigit( preview.at( 0 )) };
::std::string const multiplicity { is_product ? sc.get(): "1"s };
return product_parse_type{ component.surface() +( is_product ? preview : ""s ), new primary_parse_type { component }, multiplicity }; }
 
sum_parse_type get_sum()
{ auto result { sum_parse_type{ ""s, {} }};
product_parse_type component { get_product() };
if( component.surface() == ""s )return result;
result.append_surface( component.surface() );
result.append_addend( component );
::std::string preview;
while( true )
{ preview = sc.peek();
bool const is_sum { preview.length() > 0 &&( isalpha( preview.front() )|| preview.front() == '(' || preview.front() == '[' )};
if( !is_sum )return result;
component = get_product();
result.append_surface( component.surface() );
result.append_addend( component ); }
return sum_parse_type{ ""s, {} }; }
 
paren_parse_type get_paren()
{ ::std::string const lpar { sc.get() };
sum_parse_type const sum { get_sum() };
::std::string const rpar { sc.get() };
return paren_parse_type
{ lpar + sum.surface() + rpar, lpar, rpar, sum }; }
 
primary_parse_type get_primary()
{ auto next { sc.peek() };
if( isalpha( next.front() ))
{ name_parse_type name = get_name();
return new name_parse_type{ name }; }
if( next.front() == '(' || next.front() == '[' )
{ paren_parse_type paren = get_paren();
return new paren_parse_type{ paren }; }
return nullptr; }};
 
int main()
{ ::std::istringstream s{ "[Be(N(CH3)2)2]3" };
scanner< ::std::istringstream >sc{ ::std::move( s )};
parser_type< scanner< ::std::istringstream > >parser{ ::std::move( sc )};
sum_parse_type sum_value = parser.get_sum();
::std::cout << sum_value.surface() << '\n';
::std::cout << sum_value.description() << '\n'; }
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: