Monday, June 29, 2015

Digest for comp.lang.c++@googlegroups.com - 13 updates in 5 topics

Juha Nieminen <nospam@thanks.invalid>: Jun 29 08:18AM

> guide A:
 
> Don't use macros! OK, (...) treat them as a last resort.
> (...) And #undef them after you've used them, if possible.
 
There are things that can only be done with preprocessor macros.
assert() is the ubiquitous example. (And obviously you shouldn't
be #undeffing assert().)
 
(The reason why assert() can only be done with a macro is that it
prints the file and line where the assertion failure happened,
which is impossible in C++ proper.)
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jun 29 11:22AM +0200

On 29-Jun-15 10:18 AM, Juha Nieminen wrote:
 
> There are things that can only be done with preprocessor macros.
> assert() is the ubiquitous example. (And obviously you shouldn't
> be #undeffing assert().)
 
Also it would be unwise to #undef "errno" after use...
 
(C++14 §19.4/1 "errno shall be defined as a macro")
 
 
* * *
 
Regarding the associated issue of use of #undef in general for standard
macros, i.e. whether that's acceptable, there's the NDEBUG macro.
 
C++14 §17.6.2.2/2 "the effect of including either <cassert> or
<assert.h> depends each time on the lexically current definition of NDEBUG."
 
The dependency is each time on the existence of NDEBUG, not on any
particular definition.
 
And that does not make sense if NDEBUG is never #undef-ed.
 
So this is one case where the standard assumes and depends on client
code use of #undef for a standard macro, and I mention it as an example
that that's not always an abomination. In another posting I mentioned
another concrete example, that of using #undef to avoid warnings for a
following #define of UNICODE in Windows desktop programming. However,
UNICODE is only a de facto standard, not part of the C++ standard.
 
 
Cheers,
 
- Alf
 
--
Using Thunderbird as Usenet client, Eternal September as NNTP server.
Rosario19 <Ros@invalid.invalid>: Jun 29 01:48PM +0200

On 28 Jun 2015 19:19:46 GMT, (Stefan Ram) wrote:
 
 
> #undef should not normally be needed. Its use can lead
> to confusion with respect to the existence or meaning of
> a macro when it is used in the code
 
local macro
 
int f(void)
{
#define a b
#define c d
#define g h
 
....
 
#undef g
#undef c
#undef a
 
return 0;
 
}
David Harmon <source@netcom.com>: Jun 29 06:51AM -0700

On Mon, 29 Jun 2015 08:18:03 +0000 (UTC) in comp.lang.c++, Juha Nieminen
<nospam@thanks.invalid> wrote,
>There are things that can only be done with preprocessor macros.
>assert() is the ubiquitous example. (And obviously you shouldn't
>be #undeffing assert().)
 
Of course not. You #undef NDEBUG and #include <assert.h> again.
legalize+jeeves@mail.xmission.com (Richard): Jun 29 08:18PM

[Please do not mail me a copy of your followup]
 
David Brown <david.brown@hesbynett.no> spake the secret code
>/really/ special code, as it leads to confusion - macros should normally
>have exactly the same definition at all times in the program, or at
>least within the file.
 
I have used macros to eliminate some boilerplate when constructing a
table of values. (This was pre-std::initializer_list and {}
construction, so if I were do that code again today I might not need a
macro at all.) This is the only time I've used #undef -- once that
table is defined, then I *don't* want anyone to use the macro anymore
and therefore I #undef it. Since the table is defining data, this was
in the context of a source file, not a header file. The macro had an
intention revealing name, so it is unlikely that anyone would be using
a macro of the same name, but different meaning, elsewhere in the code.
--
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
The Computer Graphics Museum <http://computergraphicsmuseum.org>
The Terminals Wiki <http://terminals.classiccmp.org>
Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>
"Öö Tiib" <ootiib@hot.ee>: Jun 28 04:50PM -0700

On Sunday, 28 June 2015 20:22:01 UTC+3, BGB wrote:
 
> namely, if you know a value needs to be a particular way, then chances
> are the person is willing to pay whatever CPU cycles are needed to make
> it that way.
 
After we take care of size and we take care of endianness there is
still alignment to care about. ;)
Note that alignment requirements may come as surprise to many.
Sometimes even on platforms with relaxed ones. For example one will
get crash on Win32 because of alignment of XMVECTOR was not 16.
 
In real application the code that encodes or decodes information for
some binary is usually therefore separate from rest of the code to
abstract such difficulties away.
 
> picking appropriate type-sizes and setting values for things like
> whether or not the target supports misaligned access, ...
 
> I guess it could be nicer if more of this were standardized.
 
Yes, preprocessor metaprogramming is not much better than template
metaprogramming if to read it. So these things are better to keep
away from code, in a separate library.
 
> be safe" would be a waste.
 
> it would be fairly easy to compress them further, but this would require
> decoding them before they could be used, which was undesirable in this case.
 
Interesting. Doesn't TLV mean tag or type, length, value? Most of those
formats encode some sort of tag/type/length in few first bits/bytes and
rest are data bytes, potentially also TLV. So why you used offsets?
Weren't the "sub-lumps" TLV themselves?
 
> less memory waste than AVL or BST variants). likewise, because of their
> structure, it is possible to predict in advance (based on the size of
> the tree) approximately how long it will take to perform the operation.
 
One interesting tree is splay that often works best in real application.
 
> > are no need for archaic tricks like Windows-1252 or Code Page 437.
 
> granted, but in this case, it is mostly for string literals, rather than
> bulk text storage.
 
The stings of application do not typically form some sort of bulk but a
sort of dictionary of short texts.
 
 
> basically, options like Deflate or LZMA are largely ineffective for
> payloads much under 200-500 bytes or so, but are much more effective as
> payloads get bigger.
 
Those packing algorithms are all for larger texts. With relatively short
one-liners one can perhaps make some special sub-string-packing but it
will be computationally expensive to pack.
BGB <cr88192@hotmail.com>: Jun 29 02:21AM -0500

On 6/28/2015 6:50 PM, Öö Tiib wrote:
 
> In real application the code that encodes or decodes information for
> some binary is usually therefore separate from rest of the code to
> abstract such difficulties away.
 
yeah.
 
this is why the explicit endian variables could also be implicitly
misaligned. it could also be possible to specify explicit alignment via
an attribute, but this isn't currently supported.
 
the ways it is implemented generally gloss over whatever the hardware
does (so, it can still do unaligned operations even on targets which
only support aligned loads/stores, by internally using byte operations
and shifts).
 
currently, my C compiler/VM doesn't do SIMD, but this might get
implemented eventually.
 
keywords were '__bigendian' and '__ltlendian'.
 
ex:
__bigendian int x;
or:
i=*(__bigendian int *)ptr;
 
possible explicit alignment value:
__declspec(align(2)) __bigendian int x;
or (if another keyword were added):
__align(2) __bigendian int x;
 
 
 
> Yes, preprocessor metaprogramming is not much better than template
> metaprogramming if to read it. So these things are better to keep
> away from code, in a separate library.
 
usually, this is a 'whatever_conf.h' file which is copied/pasted around,
sometimes with tweaks.
 
it also does explicit-size types, partly because I often use a compiler
which until very recently did not support 'stdint' stuff...
 
 
> formats encode some sort of tag/type/length in few first bits/bytes and
> rest are data bytes, potentially also TLV. So why you used offsets?
> Weren't the "sub-lumps" TLV themselves?
 
offsets are used because this saves needing to scan over the payload
lumps and rebuild the table. granted, the cost of this probably wouldn't
be huge, but the table will be needed either way, and if it is already
present in the data, it doesn't need to be built.
 
note that the file is not read-in/loaded sequentially, but is basically
loaded into the address space and used in-place.
 
 
it is Tag/Length/Value, yes.
 
the format is vaguely akin to if IFF and ASN.1 BER were fused together.
 
ASN.1 style tags are used mostly for compact structures (with typically
about 2 bytes of overhead), with TWOCC for intermediate structures (4 or
6 bytes overhead), and FOURCC for top-level structures (8 or 12 bytes of
overhead).
 
 
* 0x00-0x1F: Public Primitive (Class=0)
* 0x20-0x3F: Public Composite (Class=1)
* 0x40-0x5F: Private Primitive (Class=2)
* 0x60-0x7F: Private Composite (Class=3)
* 0x80-0x9F: Context Primitive (Class=4)
* 0xA0-0xBF: Context Composite (Class=5)
** ccct-tttt:
*** ccc=class, ttttt=tag
*** tag=0..30, tag encoded directly
*** tag=31, tag is escape coded.
* 0xC0-0xDF: Reserved
* 0xE0-0xFF: Special Markers
** 0xE0, End Of Data
** 0xE1, len:WORD24
** 0xE2, len:BYTE
*** Context Dependent Untagged Data
** 0xE3, len:WORD24, tag:TWOCC
** 0xE4, len:WORD24, tag:FOURCC
** 0xE5, len:BYTE, tag:TWOCC
** 0xE6, len:Word56, tag:FOURCC
** 0xE7, len:WORD24, tag:EIGHTCC
** 0xE8, len:WORD24, tag:SIXTEENCC
** 0xE9, len:Word56, tag:EIGHTCC
** 0xEA, len:WORD56, tag:SIXTEENCC
*** Tagged Markers
 
I have used variations on this design for a number of formats (it
actually started out mostly in some of my video codecs).
 
 
>> structure, it is possible to predict in advance (based on the size of
>> the tree) approximately how long it will take to perform the operation.
 
> One interesting tree is splay that often works best in real application.
 
yeah.
 
splay is fast, but not necessarily all that predictable nor memory
efficient (it is more like AVL in the memory-efficiency sense, and
leaves open the possibility of an O(n) worst case).
 
 
B-Tree is not necessarily the fastest option, but should be fairly
predictable in this case.
 
like, you really don't want a random edge-case throwing a wrench in the
timing, and fouling up external electronics by not updating the IO pins
at the correct times or something.
 
nevermind if it is questionable to do high-level logic and also deal
with hardware-level IO on the same processor core, but alas... (why have
a separate ARM chip and an MCU, when you can save some money by just
doing everything on the main ARM chip?...).
 
 
>> bulk text storage.
 
> The stings of application do not typically form some sort of bulk but a
> sort of dictionary of short texts.
 
not sure I follow.
 
in the case of the VM, they are basically a pair of string tables, one
for ASCII and UTF-8, and the other for UTF-16. each string is terminated
with a NUL character.
 
for the ASCII table, string references are in terms of byte offsets,
with it depending on context how the string is encoded.
 
if C is compiled to the VM, it really doesn't care, since it has good
old 'char *', so will use pointers into the string table.
 
the script-language does care, but will implicitly declare the type as
part of the process of loading the string into a register (and, in this
case, the VM will remember the type of string).
 
 
though, granted, in this VM, the string type will be handled by
implicitly using tag bits in the reference. this allows using a
reference directly to the string-table memory, without needing an
intermediate structure (so, it is sort of like a normal 'char *'
pointer, just with a hidden type-tag in the reference).
 
 
 
> Those packing algorithms are all for larger texts. With relatively short
> one-liners one can perhaps make some special sub-string-packing but it
> will be computationally expensive to pack.
 
well, as noted, I had some limited success with MTF+Rice.
though, there isn't much that can be done with short character strings.
"Öö Tiib" <ootiib@hot.ee>: Jun 29 07:20AM -0700

On Monday, 29 June 2015 10:26:01 UTC+3, BGB wrote:
> >>>>>>> On Saturday, 27 June 2015 00:37:40 UTC+3, Mr Flibble wrote:
> >>>>>>>> On 26/06/2015 21:31, JiiPee wrote:
> >>>>>>>>> On 26/06/2015 20:39, Mr Flibble wrote:
 
... Snip for focus
 
> like, you really don't want a random edge-case throwing a wrench in the
> timing, and fouling up external electronics by not updating the IO pins
> at the correct times or something.
 
On that case RB tree is maybe most stable ... on any case it seems more
stable and generally quicker than AVL.
 
> with hardware-level IO on the same processor core, but alas... (why have
> a separate ARM chip and an MCU, when you can save some money by just
> doing everything on the main ARM chip?...).
 
You certainly may need separate processor for more demanding I/O (WiFi
network for example) otherwise yes.
 
> reference directly to the string-table memory, without needing an
> intermediate structure (so, it is sort of like a normal 'char *'
> pointer, just with a hidden type-tag in the reference).
 
I meant that if we really wan't to have byte pointers into our string
literals then there is indeed no way to keep things compressed
behind scenes. However If we want to have a "text" available in
limited occasions, for example like GNU gettext library provides
then we can have the texts compressed most of the time.
 
> > will be computationally expensive to pack.
 
> well, as noted, I had some limited success with MTF+Rice.
> though, there isn't much that can be done with short character strings.
 
If all texts in application are UTF-16 then Huffman coding compresses about
2.6 times (minus the decoder and its data of course). So the only question is
if there is big enough amount of texts to be handled by application to bother
with it.
BGB <cr88192@hotmail.com>: Jun 29 12:18PM -0500

On 6/29/2015 9:20 AM, Öö Tiib wrote:
>> at the correct times or something.
 
> On that case RB tree is maybe most stable ... on any case it seems more
> stable and generally quicker than AVL.
 
could be.
 
more analysis and testing may be needed.
 
 
checking for memory density.
( note: Implicitly assuming a slab allocator or similar, so negligible
overhead apart from alignment ).
 
say, tree node for a binary tree (BST1):
struct BiNode1 {
BiNode1 *left, *right;
SlotInfo *key;
byte depth;
//pad:3 bytes
Value val;
};
memory cost: ~24 bytes, about 33% payload.
assume: node is either a node or a leaf.
for a node, both left and right are filled and key is a pivot, nodes do
not hold a value.
for a leaf, both left and right are NULL.
 
or (BST2):
struct BiNode2 {
SlotInfo *key;
byte depth;
//pad: 7 bytes
union {
struct {
BiNode2 *left, *right;
}b;
Value val;
}u;
};
memory cost: ~16 bytes, about 50% payload.
same behavior as BST1, but reducing memory by eliminating
mutually-exclusive data.
 
BST3:
case of BST1, where each node always contains a value, reducing node counts.
each node has a value, and 1 or 2 child nodes (whereas a leaf lacks
child nodes).
 
for an order-12 B-Tree (BT1):
#define MSX_BT_KEY 12
struct BtNode {
BtNode *next;
SlotInfo *key[MAX_BT_KEY];
byte nkey;
byte depth;
//pad: 2 bytes
union {
BtNode *child[MAX_BT_KEY];
Value val[MAX_BT_KEY];
}u;
};
 
Cost: 152 bytes, 63% payload.
 
for an order-6 B-Tree (BT2):
Cost: 96 bytes, 50% payload.
 
memory estimates (count, type, total bytes, memory efficiency):
1 item(1L): BST1: 24 bytes (33.3%)
1 item(1L): BST2: 16 bytes (50.0%)
1 item(1L): BST3: 24 bytes (33.3%)
1 item(1L): BT1: 152 bytes ( 5.3%)
1 item(1N): BT2: 96 bytes ( 8.3%)
 
2 items(1N,2L): BST1: 72 bytes (22.2%)
2 items(1N,2L): BST2: 48 bytes (33.3%)
2 items(1N,1L): BST3: 48 bytes (33.3%)
2 items( 1L): BT1: 152 bytes (10.1%)
2 items( 1L): BT2: 96 bytes (16.6%)
 
4 items(3N,4L): BST1: 168 bytes (19.0%)
4 items(3N,4L): BST2: 112 bytes (28.6%)
4 items(2N,2L): BST3: 96 bytes (33.3%)
4 items( 1L): BT1: 152 bytes (21.1%)
4 items( 1L): BT2: 96 bytes (33.3%)
 
8 items(7N,8L): BST1: 360 bytes (17.8%)
8 items(7N,8L): BST2: 240 bytes (26.6%)
8 items(4N,4L): BST3: 192 bytes (33.3%)
8 items( 1L): BT1: 152 bytes (42.1%)
8 items(1N,2L): BT2: 288 bytes (22.2%)
 
16 items(15N,16L): BST1: 744 bytes (17.2%)
16 items(15N,16L): BST2: 496 bytes (25.8%)
16 items( 8N, 8L): BST3: 384 bytes (33.3%)
16 items( 1N, 2L): BT1: 456 bytes (28.1%)
16 items( 1N, 3L): BT2: 384 bytes (33.3%)
 
32 items(31N,32L): BST1: 1512 bytes (16.9%)
32 items(31N,32L): BST2: 1008 bytes (25.4%)
32 items(16N,16L): BST3: 768 bytes (33.3%)
32 items( 1N, 3L): BT1: 608 bytes (42.1%)
32 items( 1N, 5L): BT2: 576 bytes (44.4%)
 
 
so, it is a lot closer than I was thinking...
 
BST has an advantage on the memory front for small item counts, but
loses them as item counts increases.
 
though, it is possible that a B-Tree could suffer from an unfavorable
pattern of inserts which could reduce its memory efficiency (causing it
to under-perform vs a BST variant).
 
 
could rig-up some benchmarks and compare them...
 
 
>> doing everything on the main ARM chip?...).
 
> You certainly may need separate processor for more demanding I/O (WiFi
> network for example) otherwise yes.
 
a lot of things in my case are things like running motors and dealing
with external sensors and similar (some of the sensors generate PWM
signals).
 
a lot of this stuff runs in the kHz range (say, 25-50 kHz or so), so it
is necessarily to be able to respond quickly enough to keep everything
running smoothly.
 
internally, there might also be fun like interpreting G-Code or similar
(telling the machine the desired positions to move the motors to, what
RPM the tool spindle should turn, ...).
 
 
the same basic code has also been used in a small wheeled robot, and
should be applicable to other types of robots (such as ones with
articulated limbs).
 
networking is used to some extent to control these, but the network
hardware seems able to handle a lot on its own (doesn't need anywhere
near the levels of micro-management as motors or sensors)
 
 
> behind scenes. However If we want to have a "text" available in
> limited occasions, for example like GNU gettext library provides
> then we can have the texts compressed most of the time.
 
ok.
 
 
> 2.6 times (minus the decoder and its data of course). So the only question is
> if there is big enough amount of texts to be handled by application to bother
> with it.
 
dunno, it depends on the application.
 
in the VM, a lot of the string data tends to be things like imported
function names, type-signatures, ... some amount of this also tends to
be strings for any printed messages.
 
bytecode is also a big chunk of memory.
 
generally the VM's bytecode images are around 1/2 to 1/3 the size of
native x86 versions of the program (and also smaller than ARM code and
Deflate-compressed source code).
 
though, the bytecode was designed some with code density in mind. it
doesn't so much pull this off with the smallest possible opcodes, but
rather by trying to allow things to be done with a reasonably small
number of operations.
 
nevermind if the current VM goes and craps all over this by translating
the bytecode into relatively bulky threaded-code, but alas...
Juha Nieminen <nospam@thanks.invalid>: Jun 29 08:14AM

> Everybody knows that with diamond inheritance we need virtual
> inheritance.
 
You don't *need* it. It's *one possible solution* to how to handle
diamond inheritance. C++ also offers another solution (which is not
only a bit more efficient, but also feasible in some situations).
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
"Öö Tiib" <ootiib@hot.ee>: Jun 29 09:39AM -0700

On Monday, 29 June 2015 11:14:50 UTC+3, Juha Nieminen wrote:
 
> You don't *need* it. It's *one possible solution* to how to handle
> diamond inheritance. C++ also offers another solution (which is not
> only a bit more efficient, but also feasible in some situations).
 
What is the solution? Actually I would more like to see a motivating
problem. I have not met a problem to solve with it. Typical examples
from books are also awfully abstract:
 
Base
/ \
/ \
/ \
Der1 Der2
\ /
\ /
\ /
Join
 
Uhh? What these Base, 'Der1', 'Der2' and 'Join' are? I don't have those
anywhere. However ... I have just learned it for case that maybe
someday I meet a case where something somewhere needs that.
Christopher Pisz <nospam@notanaddress.com>: Jun 29 11:14AM -0500

On 6/28/2015 9:53 AM, Paul wrote:
 
> }
 
> Paul
 
I didn't examine the code too closely, but I don't really see any reason
to use shared_ptr. Just use a raw pointer.
 
Consider these things :
 
The pointers should be private to the list class and its nodes, no user
should ever see them.
 
shared pointers are for when ownership of the object is going to be
"shared", which should not be the case for objects in the list
 
ownership of the stored elements should not be shared. The list should
own them and maintain them.
 
When access to an element from the outside is requested, a copy should
be made. Thus the need to a constructor and copy constructor on any type
being contained.
 
raw pointer is faster (and simpler) than shared pointer.
 
It's easy enough to identify the operations that require a new or delete
when the list completely maintains itself.
 
 
 
--
I have chosen to troll filter/ignore all subthreads containing the
words: "Rick C. Hodgins", "Flibble", and "Islam"
So, I won't be able to see or respond to any such messages
---
"Öö Tiib" <ootiib@hot.ee>: Jun 29 06:25AM -0700

On Friday, 26 June 2015 12:12:41 UTC+3, Daniel wrote:
> On Thursday, June 25, 2015 at 9:20:20 PM UTC-4, Öö Tiib wrote:
 
Sorry didn't somehow notice it.
 
> >Math functions we fortunately expect
> > to be non-members.
 
> I gather you don't care for extension methods :-)
 
Oh not so. I just don't like "methods" that actually are "pure functions" in
my mind. For example 'std::string::substr' is fully referentially transparent
function. Substring is not property, component, aggregate (or other
associate) or product of string so it feels like a function not method.

Otherwise there is both attractive clarity and convenience in method
syntax and while there are also some questions and a controversy still
to be solved the extension methods feel good idea. Consider the two
subroutine calling syntaxes:
 
1) first_parameter.subroutine( second_parameter )
2) subroutine( first_parameter, second_parameter )
 
Clarity is that IMHO 1) says that the 'first_parameter' is the main,
non-optional IN-OUT argument of subroutine. 2) does not tell anything
like that. There are no reason why the subroutine must be declared
within class definition to achieve that clarity.
 
Convenience is that during typing 1) smarter code editors can likely offer
faster and better auto-complete choices than 2).
 
Most difficult question for me is perhaps how the (already complex)
overloading and name-hiding rules will work when extension methods
will enter the playground.
 
Controversy is like usual that every feature is possible to abuse. Some
people *will* use it for the convenience above even where 'first_parameter'
is for example optional or some SINK-IN parameter (if it is allowed) and
so the outcome looks confusing. But that can be left for coding standards
to resolve like always.
 
So I am generally thinking positively about extension methods.
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: