Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

String integer id

82 views
Skip to first unread message

malcolm...@btinternet.com

unread,
Feb 22, 2016, 9:59:51 AM2/22/16
to
I want a flyweight class that is a "string id".
That is to say, it consists of a 64 bit number which is also a string of up to seven
characters, used for passing about human-readable ids that the machine can
process as integers.

However how do I write it so that it's easy to make it a constexpr, whilst still being
convenient to call. (The ids will mostly be known at compile time, only rarely will
you have a situation when the user enters a string and it ends up being turned
into a dynamic id).
Particularly I would like to be able to switch on the id and have human-readable names
in the case conditions.

Alf P. Steinbach

unread,
Feb 22, 2016, 11:30:45 AM2/22/16
to
On 22.02.2016 15:59, malcolm...@btinternet.com wrote:
> I want a flyweight class that is a "string id".
> That is to say, it consists of a 64 bit number which is also a string of up to seven
> characters, used for passing about human-readable ids that the machine can
> process as integers.
>
> However how do I write it so that it's easy to make it a constexpr, whilst still being
> convenient to call. (The ids will mostly be known at compile time, only rarely will
> you have a situation when the user enters a string and it ends up being turned
> into a dynamic id).

Is this a correct understanding?

• Each 64-bit id is usually chosen by the programmer.

• There is a (unspecified) two-way mapping between 64-bit id and
7-character human readable string.

• You're asking how to compute the unspecified mapping at compile time.


> Particularly I would like to be able to switch on the id and have human-readable names
> in the case conditions.

Is this a correct understanding:

• Particularly you want a `constexpr` string → number computation?

Which just seems like a user defined literal.

And is this a correct understanding:

• You are free to choose a suitable mapping, and the criterion
“human-readable” is also a very loose one?


Cheers,

- Alf

malcolm...@btinternet.com

unread,
Feb 22, 2016, 12:04:36 PM2/22/16
to
On Monday, February 22, 2016 at 4:30:45 PM UTC, Alf P. Steinbach wrote:
> On 22.02.2016 15:59, malcolm...@btinternet.com wrote:
>
> Is this a correct understanding?
>
> * Each 64-bit id is usually chosen by the programmer.
>
> * There is a (unspecified) two-way mapping between 64-bit id and
> 7-character human readable string.
>
> * You're asking how to compute the unspecified mapping at compile time.
>
The idea is that the id is an unsigned 64 bit integer, which is also an asciiz string
of seven characters plus null.
So if the id is "charlie" then the id is 99 (ascii c) * 2**56 + 104 * 2**48 and so on.
So if there's some question about the ids, you can analyse the binary or
print the value out as a string, and you've got a human-meaningul enumeration
value, e.g. "charlie", "andy", "anne" and "eddie" rather than 1, 2, 3, 4.


Alf P. Steinbach

unread,
Feb 22, 2016, 1:03:44 PM2/22/16
to
Well, that's directly supported by the language, so it's in a sense
trivial. Of course it helps to know what to look for, namely user
defined literals. I already mentioned that.

General discussion of user defined literals in the FAQ:
<url: https://isocpp.org/wiki/faq/cpp11-language#udls>

Technical info, nearly as good as the standard:
<url: http://en.cppreference.com/w/cpp/language/user_literal>.

Relevant tips:

• For precondition checking you can use the `?:` conditional operator,
with e.g. throw statements. And yes that works nicely for compile time
checking, because `throw` isn't `constepxr`.

• Also, for precondition checking it can be good idea to defer the main
work to a separate implementation function (that just assumes valid
preconditions).

• Remember to cast each `char` value to unsigned.

• To check whether you really get a compile time value, use it in a
context that requires compile time value. Switch `case` is of course one
such context. Others include array size, and just as initialization of a
`constexpr` variable.

• For a C++11 solution you need to recursion to avoid a nasty complex
expression. For C++14 I believe you can use a loop. I'd just use
recursion here anyway, because it's very clear for this, and concise.


Cheers & hth.,

- Alf

Barry Schwarz

unread,
Feb 22, 2016, 2:41:19 PM2/22/16
to
For values known at compile time, #define should do what you want. For
example, the name Ann is 0x41 for the A and 0x6e for each n so
#define Al 0x416e6e /* or possibly 0x416e6e0000000000 */
will allow you to code
switch (id){
case Ann:
...

--
Remove del for email

Ian Collins

unread,
Feb 22, 2016, 3:13:48 PM2/22/16
to
Barry Schwarz wrote:
> On Mon, 22 Feb 2016 06:59:14 -0800 (PST),
> malcolm...@btinternet.com wrote:
>
>> I want a flyweight class that is a "string id".
>> That is to say, it consists of a 64 bit number which is also a string of up to seven
>> characters, used for passing about human-readable ids that the machine can
>> process as integers.
>>
>> However how do I write it so that it's easy to make it a constexpr, whilst still being
>> convenient to call. (The ids will mostly be known at compile time, only rarely will
>> you have a situation when the user enters a string and it ends up being turned
>> into a dynamic id).
>> Particularly I would like to be able to switch on the id and have human-readable names
>> in the case conditions.
>
> For values known at compile time, #define should do what you want.

This is comp.lang.c++, cont comp.lang.c!

--
Ian Collins

malcolm...@btinternet.com

unread,
Feb 22, 2016, 4:22:38 PM2/22/16
to
On Monday, February 22, 2016 at 6:03:44 PM UTC, Alf P. Steinbach wrote:
> On 22.02.2016 18:04, malcolm...@btinternet.com wrote:
> > On Monday, February 22, 2016 at 4:30:45 PM UTC, Alf P. Steinbach wrote:
> >> On 22.02.2016 15:59, malcolm...@btinternet.com wrote:
> >>
> >> Is this a correct understanding?
> >>
> >> * Each 64-bit id is usually chosen by the programmer.
> >>
> >> * There is a (unspecified) two-way mapping between 64-bit id and
> >> 7-character human readable string.
> >>
> >> * You're asking how to compute the unspecified mapping at compile time.
> >>
> > The idea is that the id is an unsigned 64 bit integer, which is also an asciiz string
> > of seven characters plus null.
> > So if the id is "charlie" then the id is 99 (ascii c) * 2**56 + 104 * 2**48 and so on.
> > So if there's some question about the ids, you can analyse the binary or
> > print the value out as a string, and you've got a human-meaningul enumeration
> > value, e.g. "charlie", "andy", "anne" and "eddie" rather than 1, 2, 3, 4.
>
> Well, that's directly supported by the language, so it's in a sense
> trivial. Of course it helps to know what to look for, namely user
> defined literals. I already mentioned that.
>
> General discussion of user defined literals in the FAQ:
> <url: https://isocpp.org/wiki/faq/cpp11-language#udls>
>
> Technical info, nearly as good as the standard:
> <url: http://en.cppreference.com/w/cpp/language/user_literal>.
>
> Relevant tips:
>
> * For precondition checking you can use the `?:` conditional operator,
> with e.g. throw statements. And yes that works nicely for compile time
> checking, because `throw` isn't `constepxr`.
>
> * Also, for precondition checking it can be good idea to defer the main
> work to a separate implementation function (that just assumes valid
> preconditions).
>
> * Remember to cast each `char` value to unsigned.
>
> * To check whether you really get a compile time value, use it in a
> context that requires compile time value. Switch `case` is of course one
> such context. Others include array size, and just as initialization of a
> `constexpr` variable.
>
> * For a C++11 solution you need to recursion to avoid a nasty complex
> expression. For C++14 I believe you can use a loop. I'd just use
> recursion here anyway, because it's very clear for this, and concise.
>
>
It's operator "".

Great, thanks, that's what I was looking for.

Paavo Helde

unread,
Feb 22, 2016, 5:33:01 PM2/22/16
to
No problem, in C++ we can have the same:

enum constants: uint64_t {
Ann = 0x6e6e41,
Betty = 0x7974746542,
};

Or even combine this with user literals:

#include <iostream>
#include <string>
#include <stdint.h>

constexpr uint64_t operator""_id(const char* p, size_t n) {
return static_cast<unsigned char>(*p) | (n>0 ? operator""_id(p+1, n-1)
: uint64_t(0))<<8;
}

enum constants: uint64_t {
Ann = "Ann"_id,
Betty = "Betty"_id,
};

std::string StrFromId(uint64_t x) {
std::string s(reinterpret_cast<const char*>(&x), 8);
return s.substr(0, s.find(char(0)));
}


int main() {

uint64_t arr[] = {Ann, Betty};

for(auto x: arr) {
switch(x) {
case Ann:
std::cout << "A " << StrFromId(x) << "\n";
break;
case Betty:
std::cout << "B " << StrFromId(x) << "\n";
break;
}
}
}

Output (little-endian):
A Ann
B Betty

Richard

unread,
Feb 22, 2016, 5:40:07 PM2/22/16
to
[Please do not mail me a copy of your followup]

Paavo Helde <myfir...@osa.pri.ee> spake the secret code
<OYOdncUI350MEVbL...@giganews.com> thusly:

>No problem, in C++ we can have the same:
>
>enum constants: uint64_t {
> Ann = 0x6e6e41,
> Betty = 0x7974746542,
>};
>
>Or even combine this with user literals:
>
>#include <iostream>
>#include <string>
>#include <stdint.h>
>
>constexpr uint64_t operator""_id(const char* p, size_t n) {
> return static_cast<unsigned char>(*p) | (n>0 ? operator""_id(p+1, n-1)
>: uint64_t(0))<<8;
>}
>
>enum constants: uint64_t {
> Ann = "Ann"_id,
> Betty = "Betty"_id,
>};

For this to be visible as the string "Ann\0" in memory, doesn't this
assume a certain byte order for integral types?
--
"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>

Ben Bacarisse

unread,
Feb 22, 2016, 6:02:37 PM2/22/16
to
By "print the value as a string", I suspect you mean simply treating a
pointer to the integer as a character pointer. If you want to do that,
you run into trouble with endianness if you build the value
arithmetically (as your example suggest). For little-endian machines
you need the bytes to be packed with the other significance:

template <typename T>
static constexpr T make_id(const char *lit, std::size_t len, T r)
{
return len ? make_id(lit, len - 1, (r << 8) + lit[len-1]) : r;
}

constexpr unsigned long long operator "" _id(const char *lit, std::size_t len)
{
return make_id(lit, len >= sizeof 0ULL ? sizeof 0ULL - 1 : len, 0ULL);
}

I have not been able to come up with a constexpr method that puts the
bytes into an integer in address order.

--
Ben.

Öö Tiib

unread,
Feb 22, 2016, 6:16:49 PM2/22/16
to
There are no standard trick neither in C nor in C++ to determine
endianness compile time. Any type punning is forbidden in 'constexpr'
functions. For practical purposes Boost header file endian.hpp covers
endianness for large amount of platforms.

Alf P. Steinbach

unread,
Feb 22, 2016, 6:46:54 PM2/22/16
to
On 22.02.2016 23:39, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <OYOdncUI350MEVbL...@giganews.com> thusly:
>
>> No problem, in C++ we can have the same:
>>
>> enum constants: uint64_t {
>> Ann = 0x6e6e41,
>> Betty = 0x7974746542,
>> };
>>
>> Or even combine this with user literals:
>>
>> #include <iostream>
>> #include <string>
>> #include <stdint.h>
>>
>> constexpr uint64_t operator""_id(const char* p, size_t n) {
>> return static_cast<unsigned char>(*p) | (n>0 ? operator""_id(p+1, n-1)
>> : uint64_t(0))<<8;
>> }
>>
>> enum constants: uint64_t {
>> Ann = "Ann"_id,
>> Betty = "Betty"_id,
>> };
>
> For this to be visible as the string "Ann\0" in memory, doesn't this
> assume a certain byte order for integral types?
>

I think Paavo's code is way too portable, so:

#include <iostream>
#include <string>
#include <stdint.h>
using namespace std;

constexpr
auto adjoined( uint64_t const a, uint64_t const b )
-> uint64_t
{ return (a << 32) | b; }

enum constants: uint64_t { Ann = 'nnA', Betty = adjoined( 'y',
'tteB' ) };

auto str_from_id( uint64_t const x )
-> std::string
{ return reinterpret_cast<const char*>( &x ); }

auto main() -> int
{
uint64_t const arr[] = {Ann, Betty};
for( auto const x: arr ) switch( x )
{
case Ann:
cout << "A " << str_from_id( x ) << "\n";
break;
case Betty:
cout << "B " << str_from_id( x ) << "\n";
break;
}
}


This avoids using newfangled stuff like C++11 user defined literals, and
leverages the good old C syntax that BEEN THERE FOR A REASON since,
well, since the 1970s!

After all, what could possibly go wrong?


Cheers!,

- Alf

Jerry Stuckle

unread,
Feb 22, 2016, 7:55:00 PM2/22/16
to
Wrong again. But then I wouldn't expect a troll to understand.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

Alf P. Steinbach

unread,
Feb 22, 2016, 8:26:55 PM2/22/16
to
Öö Tiib is correct. There are no known tricks, and absolutely no
standard or well known ones. The [1] C FAQ mentions a possible trick,

'ABCD' == 0x41424344

but clarifies that

“this isn't reliable, either”

E.g., reportedly some [2] Solaris/SPARC compilers differ in the result
of that expression (or similar expression), on the same platform.


> But then I wouldn't expect a troll to understand.

Again, here you're wrong, possibly a case of mistaken identity.


Cheers & hth.,

- Alf

[1] <url: http://www.c-faq.com/cpp/ifendian.html>
[2] <url: http://stackoverflow.com/a/4275412/464581>

Jerry Stuckle

unread,
Feb 22, 2016, 8:35:46 PM2/22/16
to
On 2/22/2016 8:26 PM, Alf P. Steinbach wrote:
> On 23.02.2016 01:54, Jerry Stuckle wrote:
>> On 2/22/2016 6:16 PM, Öö Tiib wrote:
>>>
>>> There are no standard trick neither in C nor in C++ to determine
>>> endianness compile time. Any type punning is forbidden in 'constexpr'
>>> functions. For practical purposes Boost header file endian.hpp covers
>>> endianness for large amount of platforms.
>>>
>>
>> Wrong again.
>
> Öö Tiib is correct. There are no known tricks, and absolutely no
> standard or well known ones. The [1] C FAQ mentions a possible trick,
>
> 'ABCD' == 0x41424344
>
> but clarifies that
>
> “this isn't reliable, either”
>
> E.g., reportedly some [2] Solaris/SPARC compilers differ in the result
> of that expression (or similaisr expression), on the same platform.
>
>
>> But then I wouldn't expect a troll to understand.
>
> Again, here you're wrong, possibly a case of mistaken identity.
>
>
> Cheers & hth.,
>
> - Alf
>
> [1] <url: http://www.c-faq.com/cpp/ifendian.html>
> [2] <url: http://stackoverflow.com/a/4275412/464581>
>

Wrong again. There are ways, using unions. But I'm not going to get
into an argument with a troll.

Richard

unread,
Feb 22, 2016, 9:31:37 PM2/22/16
to
[Please do not mail me a copy of your followup]

Jerry Stuckle <jstu...@attglobal.net> spake the secret code
<nagcrj$nvc$1...@jstuckle.eternal-september.org> thusly:

>But I'm not going to get into an argument with a troll.

Calling anyone who disagrees with you in the slightest a "troll" is
stupid. *PLONK*

Alf has been a long time contributor to raising the signal of this
newsgroup out of the noise.

If Alf is a troll, then there are no people on this planet discussing
C++ that aren't trolls.

Alf P. Steinbach

unread,
Feb 22, 2016, 9:35:11 PM2/22/16
to
On 23.02.2016 02:35, Jerry Stuckle wrote:
> On 2/22/2016 8:26 PM, Alf P. Steinbach wrote:
>> On 23.02.2016 01:54, Jerry Stuckle wrote:
>>> On 2/22/2016 6:16 PM, Öö Tiib wrote:
>>>>
>>>> There are no standard trick neither in C nor in C++ to determine
>>>> endianness compile time. Any type punning is forbidden in 'constexpr'
>>>> functions. For practical purposes Boost header file endian.hpp covers
>>>> endianness for large amount of platforms.
>>>
>>> Wrong again.
>
> Wrong again. There are ways, using unions.

That's formally UB and won't compile with recent clang.

A similar trick based on pointer arithmetic, `Ptr_b() + (a - Ptr_a())`,
won't compile either: the modern compilers are just too good at
implementing the IMHO too restrictive language standard.

E.g. the standard could have allowed casting to pointer to same size
fundamental type, and that would have allowed user defined strongly
typed string literals. Which I would like. But alas, it doesn't.


> But I'm not going to get into an argument with a troll.

You're not here for learning, that much is clear.


Cheers, you idiot, :)

- Alf

Jerry Stuckle

unread,
Feb 22, 2016, 9:38:12 PM2/22/16
to
On 2/22/2016 9:34 PM, Alf P. Steinbach wrote:
> On 23.02.2016 02:35, Jerry Stuckle wrote:
>> On 2/22/2016 8:26 PM, Alf P. Steinbach wrote:
>>> On 23.02.2016 01:54, Jerry Stuckle wrote:
>>>> On 2/22/2016 6:16 PM, Öö Tiib wrote:
>>>>>
>>>>> There are no standard trick neither in C nor in C++ to determine
>>>>> endianness compile time. Any type punning is forbidden in 'constexpr'
>>>>> functions. For practical purposes Boost header file endian.hpp covers
>>>>> endianness for large amount of platforms.
>>>>
>>>> Wrong again.
>>
>> Wrong again. There are ways, using unions.
>
> That's formally UB and won't compile with recent clang.
>

Wrong again.

> A similar trick based on pointer arithmetic, `Ptr_b() + (a - Ptr_a())`,
> won't compile either: the modern compilers are just too good at
> implementing the IMHO too restrictive language standard.
>

Again, wrong.

> E.g. the standard could have allowed casting to pointer to same size
> fundamental type, and that would have allowed user defined strongly
> typed string literals. Which I would like. But alas, it doesn't.
>
>
>> But I'm not going to get into an argument with a troll.
>
> You're not here for learning, that much is clear.
>
>
> Cheers, you idiot, :)
>
> - Alf
>

And, of course, everything I find on the internet is the truth, the
whole truth, and nothing but the truth. So help me Google.

Jerry Stuckle

unread,
Feb 22, 2016, 9:42:10 PM2/22/16
to
On 2/22/2016 9:31 PM, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Jerry Stuckle <jstu...@attglobal.net> spake the secret code
> <nagcrj$nvc$1...@jstuckle.eternal-september.org> thusly:
>
>> But I'm not going to get into an argument with a troll.
>
> Calling anyone who disagrees with you in the slightest a "troll" is
> stupid. *PLONK*
>
> Alf has been a long time contributor to raising the signal of this
> newsgroup out of the noise.
>
> If Alf is a troll, then there are no people on this planet discussing
> C++ that aren't trolls.
>

You're right. I'm not here to learn from idiots or trolls. And I don't
care how long someone has been "contributing" to a group - newsgroup,
forum or whatever. His *current* "contributions" define whether he is a
troll or not.

Just because I'm new here does *not* mean I haven't been programming in
C++ for a while. In fact, it's been about 28 years. And whether *you*
think I know what I'm talking about or not is immaterial to me.

Google

unread,
Feb 22, 2016, 10:36:40 PM2/22/16
to
On Mon, 22 Feb 2016 21:38:02 -0500, Jerry Stuckle
<jstu...@attglobal.net> wrote:

>And, of course, everything I find on the internet is the truth, the
>whole truth, and nothing but the truth. So help me Google.

AI0K
JERRY D STUCKLE
9920 BRIXTON LN
BETHESDA, MD 20817-1501

Alf P. Steinbach

unread,
Feb 22, 2016, 10:59:49 PM2/22/16
to
On 23.02.2016 03:42, Jerry Stuckle wrote:
> On 2/22/2016 9:31 PM, Richard wrote:
>>
>> *PLONK*
>
> Whether *you* think …

Richard can't hear you when you post with that mail address, unless
someone quotes you, because he's told his newsreader to ignore any
posting of yours. That's [1] what the word “plonk” means. Another way to
phrase it, based on a particular now archaic technology, is that you've
been added to his “killfile” (a kind of spam filter).

Signaling the killfile action with a “plonk” is a courtesy to let you
know that he will not see your postings, so that you can avoid fruitless
efforts to engage him – like the posting I'm replying to.

Originally the term “plonk” was very derogatory, evoking associations to
“the sound of something solid landing” (and you can guess where). But
there was also “plink” for a much more light-weight something landing,
so “plonk” paradoxically also indicated some measure of respect. But
during the late 1990s the meaning of “plonk” evolved to a more neutral
one of just hey, our interactions have become irreparably ungood, I'm
opting out of it and I will not even see your postings.


Cheers & hth.,

- Alf


Notes:
[1] <url: http://www.hacker-dictionary.com/terms/plonk>

woodb...@gmail.com

unread,
Feb 22, 2016, 11:48:39 PM2/22/16
to
On Monday, February 22, 2016 at 8:38:12 PM UTC-6, Jerry Stuckle wrote:
>
> And, of course, everything I find on the internet is the truth, the
> whole truth, and nothing but the truth. So help me Google.
>

How about

https://duckduckgo.com

? They don't track you and in my opinion are more
trustworthy than Google.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Paavo Helde

unread,
Feb 23, 2016, 3:01:45 AM2/23/16
to
On 23.02.2016 0:39, Richard wrote:
> [Please do not mail me a copy of your followup]
>
> Paavo Helde <myfir...@osa.pri.ee> spake the secret code
> <OYOdncUI350MEVbL...@giganews.com> thusly:
>
>> No problem, in C++ we can have the same:
>>
>> enum constants: uint64_t {
>> Ann = 0x6e6e41,
>> Betty = 0x7974746542,
>> };
>>
>> Or even combine this with user literals:
>>
>> #include <iostream>
>> #include <string>
>> #include <stdint.h>
>>
>> constexpr uint64_t operator""_id(const char* p, size_t n) {
>> return static_cast<unsigned char>(*p) | (n>0 ? operator""_id(p+1, n-1)
>> : uint64_t(0))<<8;
>> }
>>
>> enum constants: uint64_t {
>> Ann = "Ann"_id,
>> Betty = "Betty"_id,
>> };
>
> For this to be visible as the string "Ann\0" in memory, doesn't this
> assume a certain byte order for integral types?
>

Yes, you are right. The problem with endianness is that the bytes are
not guaranteed to be in a strictly monotonic order. Others are claiming
that there is no standard and reliable way to find the endianness out at
compile time (for constexpr). However, I started to think isn't it
possible to reuse the user literal mechanism itself, even if it is not
good for finding out the actual endianness it should be good for the
user literals themselves.

(Warning: I do not have access to any big- or mixed-endian machines for
testing, so this may contain bugs, and certainly it can be simplified):

#include <iostream>
#include <string>
#include <stdint.h>

constexpr uint64_t operator""_idraw(const char* p, size_t n) {
return static_cast<unsigned char>(*p) | (n>0 ? operator""_idraw(p+1,
n-1): uint64_t(0))<<8;
}

constexpr uint64_t Fill64(uint64_t c) {
return c | c<<8 | c<<16 | c<<24 | c<<32 | c<<40 | c<<48 | c<<56;
}

constexpr uint64_t SelectByte(int pos) {
return
pos==0 ? "\xff"_idraw :
(pos==1 ? "\x00\xff"_idraw :
(pos==2 ? "\x00\x00\xff"_idraw :
(pos==3 ? "\x00\x00\x00\xff"_idraw :
(pos==4 ? "\x00\x00\x00\x00\xff"_idraw :
(pos==5 ? "\x00\x00\x00\x00\x00\xff"_idraw :
(pos==6 ? "\x00\x00\x00\x00\x00\x00\xff"_idraw :
(pos==7 ? "\x00\x00\x00\x00\x00\x00\x00\xff"_idraw : 0)))))));
}

constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return (Fill64(static_cast<unsigned char>(*p)) & SelectByte(pos)) |
(n>0 ? IdFromString(p+1, n-1, pos+1) : uint64_t(0));
}

constexpr uint64_t operator""_id(const char* p, size_t n) {
return IdFromString(p, n, 0);
}

enum constants: uint64_t {
Ann = "Ann"_id,
Betty = "Betty"_id,
};

std::string StrFromId(uint64_t x) {
std::string s(reinterpret_cast<const char*>(&x), 8);
return s.substr(0, s.find(char(0)));
}


int main() {

uint64_t arr[] = {Ann, Betty, "Caroline"_id, "Delilah"_id};

for(auto x: arr) {
switch(x) {
case Ann:
std::cout << "A " << StrFromId(x) << "\n";
break;
case Betty:
std::cout << "B " << StrFromId(x) << "\n";
break;
case "Caroline"_id:
std::cout << "C " << StrFromId(x) << "\n";
break;
case "Delilah"_id:
std::cout << "D " << StrFromId(x) << "\n";
break;
}
}
}


David Brown

unread,
Feb 23, 2016, 3:16:20 AM2/23/16
to
On 23/02/16 02:35, Jerry Stuckle wrote:
> On 2/22/2016 8:26 PM, Alf P. Steinbach wrote:
>> On 23.02.2016 01:54, Jerry Stuckle wrote:
>>> On 2/22/2016 6:16 PM, Öö Tiib wrote:
>>>>
>>>> There are no standard trick neither in C nor in C++ to determine
>>>> endianness compile time. Any type punning is forbidden in 'constexpr'
>>>> functions. For practical purposes Boost header file endian.hpp covers
>>>> endianness for large amount of platforms.
>>>>
>>>
>>> Wrong again.
>>
>> Öö Tiib is correct. There are no known tricks, and absolutely no
>> standard or well known ones. The [1] C FAQ mentions a possible trick,
>>
> Wrong again. There are ways, using unions. But I'm not going to get
> into an argument with a troll.
>

I would like to know of a reliable, standard way of identifying
endianness at compile time. Bonus points if it works in C too. I don't
believe such a method exists, but you state it with such confidence.
There are plenty of ways of detecting endianness at run-time, and for
many of them compilers can typically optimise the check and
pre-calculate it:

#define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)

But such checks are not constant expressions - you cannot use the result
in things like static initialisers, constexpr expressions, static
asserts, #if directives, etc.

Most toolchains have some sort of pre-defined compiler macros or a
header file with macros that can be used to determine endianness (like
gcc's __BYTE_ORDER__ and __ORDER_LITTLE_ENDIAN__, so there are plenty of
implementation-specific methods.

A compile-time constant expression that relies on nothing beyond the
standards would be fascinating - please post it here.



David Brown

unread,
Feb 23, 2016, 3:25:20 AM2/23/16
to
On 23/02/16 04:36, Google wrote:
> On Mon, 22 Feb 2016 21:38:02 -0500, Jerry Stuckle
> <jstu...@attglobal.net> wrote:
>
>> And, of course, everything I find on the internet is the truth, the
>> whole truth, and nothing but the truth. So help me Google.
>
<snip>

I don't know who posted this, but it is inappropriate behaviour. It is
fine to condemn a posters style, and it is fine to be so frustrated with
childish posts that you killfile them. But it is /not/ fine to post
personal information, even if it is already available to anyone with a
web browser.

In a Usenet group, you accept people as they come, or you argue with
them, or you ignore them. Posts like this are harassment.


Juha Nieminen

unread,
Feb 23, 2016, 4:18:17 AM2/23/16
to
malcolm...@btinternet.com wrote:
> That is to say, it consists of a 64 bit number which is also a string of up to seven
> characters, used for passing about human-readable ids that the machine can
> process as integers.

Given that 64 bits is 8 bytes, it is physically impossible to represent a
64-bit value with 7 characters. (The fact that you want it to be readable
reduces the range even more.)

--- news://freenews.netfront.net/ - complaints: ne...@netfront.net ---

malcolm...@btinternet.com

unread,
Feb 23, 2016, 6:16:20 AM2/23/16
to
On Tuesday, February 23, 2016 at 9:18:17 AM UTC, Juha Nieminen wrote:
> malcolm...@btinternet.com wrote:
> > That is to say, it consists of a 64 bit number which is also a string of up to seven
> > characters, used for passing about human-readable ids that the machine can
> > process as integers.
>
> Given that 64 bits is 8 bytes, it is physically impossible to represent a
> 64-bit value with 7 characters. (The fact that you want it to be readable
> reduces the range even more.)
>
We're not representing 64 bit values with 7-character string, we're representing
7 character strings as 64 bit values.

Jerry Stuckle

unread,
Feb 23, 2016, 8:32:40 AM2/23/16
to
On 2/22/2016 10:59 PM, Alf P. Steinbach wrote:
> On 23.02.2016 03:42, Jerry Stuckle wrote:
>> On 2/22/2016 9:31 PM, Richard wrote:
>>>
>>> *PLONK*
>>
>> Whether *you* think …
>
> Richard can't hear you when you post with that mail address, unless
> someone quotes you, because he's told his newsreader to ignore any
> posting of yours. That's [1] what the word “plonk” means. Another way to
> phrase it, based on a particular now archaic technology, is that you've
> been added to his “killfile” (a kind of spam filter).
>

So what? I know what plonk means. And quite frankly, I don't give a damn.

> Signaling the killfile action with a “plonk” is a courtesy to let you
> know that he will not see your postings, so that you can avoid fruitless
> efforts to engage him – like the posting I'm replying to.
>

Again, I don't really give a damn.

> Originally the term “plonk” was very derogatory, evoking associations to
> “the sound of something solid landing” (and you can guess where). But
> there was also “plink” for a much more light-weight something landing,
> so “plonk” paradoxically also indicated some measure of respect. But
> during the late 1990s the meaning of “plonk” evolved to a more neutral
> one of just hey, our interactions have become irreparably ungood, I'm
> opting out of it and I will not even see your postings.
>
>
> Cheers & hth.,
>
> - Alf
>
>
> Notes:
> [1] <url: http://www.hacker-dictionary.com/terms/plonk>
>

Gee, we used that way back in the early 80's when usenet was in its
infancy. And it wasn't positive then, either.

But then I also look at where it's coming from. So frankly, my dear, I
don't give a damn.

Jerry Stuckle

unread,
Feb 23, 2016, 8:33:56 AM2/23/16
to
It's just what is expected from the trolls here. And this one is a very
dumb troll, at that.

David Brown

unread,
Feb 23, 2016, 9:44:12 AM2/23/16
to
On 23/02/16 14:33, Jerry Stuckle wrote:
> On 2/23/2016 3:25 AM, David Brown wrote:
>> On 23/02/16 04:36, Google wrote:
>>> On Mon, 22 Feb 2016 21:38:02 -0500, Jerry Stuckle
>>> <jstu...@attglobal.net> wrote:
>>>
>>>> And, of course, everything I find on the internet is the truth, the
>>>> whole truth, and nothing but the truth. So help me Google.
>>>
>> <snip>
>>
>> I don't know who posted this, but it is inappropriate behaviour. It is
>> fine to condemn a posters style, and it is fine to be so frustrated with
>> childish posts that you killfile them. But it is /not/ fine to post
>> personal information, even if it is already available to anyone with a
>> web browser.
>>
>> In a Usenet group, you accept people as they come, or you argue with
>> them, or you ignore them. Posts like this are harassment.
>>
>>
>
> It's just what is expected from the trolls here. And this one is a very
> dumb troll, at that.
>

Trolls, no matter what reasonable and common definition you use, have
been very rare in this group (your opinion on who is or is not a troll
matters little when it is so contrary to the rest of the group).
Amongst the mostly on-topic and helpful posts, we get some pointless
posts, some irritating posts, and occasionally rude posts, but seldom
trolling posts.

No, the post here was /not/ what I expect from people in this group -
that is why I react against it. I don't think it really counts as
trolling either. I am not sure /what/ it counts as, but I don't like it.

Jerry Stuckle

unread,
Feb 23, 2016, 11:21:56 AM2/23/16
to
It is trolling, plain and simple, according to the commonly used
definition for the last 20+ years. As are twisting people's words,
ignoring facts someone else posts and other things I've seen in this group.

Maybe you don't think it's trolling. But this post does not surprise me
in the least. And the poster was even too chicken to use his own name.
Just another proof of trolls being here.

Paavo Helde

unread,
Feb 23, 2016, 11:23:46 AM2/23/16
to
On 23.02.2016 10:16, David Brown wrote:
> On 23/02/16 02:35, Jerry Stuckle wrote:
>> On 2/22/2016 8:26 PM, Alf P. Steinbach wrote:
>>> On 23.02.2016 01:54, Jerry Stuckle wrote:
>>>> On 2/22/2016 6:16 PM, Öö Tiib wrote:
>>>>>
>>>>> There are no standard trick neither in C nor in C++ to determine
>>>>> endianness compile time. Any type punning is forbidden in 'constexpr'
>>>>> functions. For practical purposes Boost header file endian.hpp covers
>>>>> endianness for large amount of platforms.
>>>>>
>>>>
>>>> Wrong again.
>>>
>>> Öö Tiib is correct. There are no known tricks, and absolutely no
>>> standard or well known ones. The [1] C FAQ mentions a possible trick,
>>>
>> Wrong again. There are ways, using unions. But I'm not going to get
>> into an argument with a troll.
>>
>
> I would like to know of a reliable, standard way of identifying
> endianness at compile time. Bonus points if it works in C too. I don't
> believe such a method exists, but you state it with such confidence.
> There are plenty of ways of detecting endianness at run-time, and for
> many of them compilers can typically optimise the check and
> pre-calculate it:
>
> #define I_AM_LITTLE (((union { unsigned x; unsigned char c; }){1}).c)
>
> But such checks are not constant expressions - you cannot use the result
> in things like static initialisers, constexpr expressions, static
> asserts, #if directives, etc.

Are these constexpr limitations (like banning reinterpret_cast) there
because of cross-compilation? Is it that if reinterpret_cast were
allowed in constexpr, the compiler would need to emulate the target
processor, whereas by current rules it only has to calculate the correct
portable value?


Alf P. Steinbach

unread,
Feb 23, 2016, 1:15:42 PM2/23/16
to
On 23.02.2016 09:01, Paavo Helde wrote:
>
> [snip] The problem with endianness is that the bytes are
> not guaranteed to be in a strictly monotonic order. Others are claiming
> that there is no standard and reliable way to find the endianness out at
> compile time (for constexpr). However, I started to think isn't it
> possible to reuse the user literal mechanism itself, even if it is not
> good for finding out the actual endianness it should be good for the
> user literals themselves.

If that were possible then it could serve as a way to determine
endianness, which would be great.


> (Warning: I do not have access to any big- or mixed-endian machines for
> testing, so this may contain bugs, and certainly it can be simplified):

I suspect that this is a late-night posting.

I sometimes do that. ;-)

Happily the net is full of critics.
Okay, let's first examine

constexpr uint64_t operator""_idraw(const char* p, size_t n) {
return static_cast<unsigned char>(*p) | (n>0 ?
operator""_idraw(p+1, n-1): uint64_t(0))<<8;
}

constexpr uint64_t SelectByte(int pos) {
return
pos==0 ? "\xff"_idraw :
(pos==1 ? "\x00\xff"_idraw :
(pos==2 ? "\x00\x00\xff"_idraw :
(pos==3 ? "\x00\x00\x00\xff"_idraw :
(pos==4 ? "\x00\x00\x00\x00\xff"_idraw :
(pos==5 ? "\x00\x00\x00\x00\x00\xff"_idraw :
(pos==6 ? "\x00\x00\x00\x00\x00\x00\xff"_idraw :
(pos==7 ? "\x00\x00\x00\x00\x00\x00\x00\xff"_idraw : 0)))))));
}

This can be replaced with just

constexpr uint64_t SelectByte(int pos) {
return (pos >= 8? 0 : uint64_t( 0xFF ) << 8*pos);
}

That's a good code transformation, I think. :)

Then this:

constexpr uint64_t Fill64(uint64_t c) {
return c | c<<8 | c<<16 | c<<24 | c<<32 | c<<40 | c<<48 | c<<56;
}

constexpr uint64_t SelectByte(int pos) {
return (pos >= 8? 0 : uint64_t( 0xFF ) << 8*pos);
}

constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return (Fill64(static_cast<unsigned char>(*p)) &
SelectByte(pos)) | (n>0 ? IdFromString(p+1, n-1, pos+1) : uint64_t(0));

… can be replaced with just


constexpr
auto left_shifted( unsigned char const val, int const distance )
-> uint64_t
{ return (distance >= 64? 0 : uint64_t( val ) << distance); }

constexpr uint64_t IdFromString(const char* p, size_t n, int pos) {
return left_shifted( *p, 8*pos ) | (n>0 ? IdFromString(p+1,
n-1, pos+1) : uint64_t(0));
}

And at this point it's clear that the code does an endian-agnostic
conversion from a base 256 number specification, to number, just as the
earlier programs.

• • •

The endianness issue can instead be addressed in the `StrFromId`
function, where one is not constrained by the `constexpr` limitations.

E.g. a strategic little call to `std::reverse` will do the trick.


Cheers!,

- Alf

Paavo Helde

unread,
Feb 23, 2016, 2:40:47 PM2/23/16
to
On 23.02.2016 20:15, Alf P. Steinbach wrote:
> On 23.02.2016 09:01, Paavo Helde wrote:
>>
>> [snip] The problem with endianness is that the bytes are
>> not guaranteed to be in a strictly monotonic order. Others are claiming
>> that there is no standard and reliable way to find the endianness out at
>> compile time (for constexpr). However, I started to think isn't it
>> possible to reuse the user literal mechanism itself, even if it is not
>> good for finding out the actual endianness it should be good for the
>> user literals themselves.
>
> If that were possible then it could serve as a way to determine
> endianness, which would be great.
>
>
>> (Warning: I do not have access to any big- or mixed-endian machines for
>> testing, so this may contain bugs, and certainly it can be simplified):
>
> I suspect that this is a late-night posting.

No, this was an early-morning posting before sufficient coffee intake ;-)

>
> And at this point it's clear that the code does an endian-agnostic
> conversion from a base 256 number specification, to number, just as the
> earlier programs.

Yeah, I was having a growing suspicion of the same ...

> The endianness issue can instead be addressed in the `StrFromId`
> function, where one is not constrained by the `constexpr` limitations.

True, but I think someone wanted to see the strings in memory while
debugging. But for that purpose the endianness is in practice easily
detected by the relevant macros and in the remote chance the program
gets it wrong then it is easy enough to fix and recompile.

Anyway, thanks for demolishing my monster!
Paavo

David Brown

unread,
Feb 23, 2016, 4:29:21 PM2/23/16
to
I don't know. I suspect it is more of a historical limitation - there
are many things that a modern compiler can calculate at compile time,
which early compilers could not do. If something is legal as a constant
expression, then any compiler, even an unsophisticated and unoptimising
one, has to figure it out at compile time - otherwise you would end up
with code that was legal on one compiler and illegal on another one. I
suppose the standards /could/ say "whether an expression using a
reinterpret_cast is a constant expression or not is implementation
dependent", but I think that would add a good deal of complications to
the language.

But Jerry is going to show us a compile-time constant expression to
detect endianness using pure standard C++, so that will settle the matter.


0 new messages