- casting that's a lot of extra typing :-) - 1 Update
- Read again, i correct a typo because i write fast... - 2 Updates
- industrial code (over flow...) - 10 Updates
- More about computing and parallel computing.. - 1 Update
- is there a C++ version of the strtok() function? - 3 Updates
- Undefined Behaviour - 1 Update
- is there a C++ version of the strtok() function? - 1 Update
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. |