[HN Gopher] ZPL: (Almost) C99 Powerkit
       ___________________________________________________________________
        
       ZPL: (Almost) C99 Powerkit
        
       Author : up2isomorphism
       Score  : 60 points
       Date   : 2021-03-20 13:47 UTC (9 hours ago)
        
 (HTM) web link (github.com)
 (TXT) w3m dump (github.com)
        
       | jart wrote:
       | It looks like ZPL has its own memcpy() implementation which is a
       | work in progress. Assuming the author posted this as a Show HN
       | kind of thread, here's some feedback I could offer based on my
       | experience implementing that function.
       | 
       | It goes pretty quick on the machines I've used so far to have an
       | indirect branch with overlapping moves. Here's what that looks
       | like in "pure c" for gcc and clang.
       | https://github.com/jart/cosmopolitan/blob/master/libc/str/me...
       | memcpy is hard to implement in pure c99 because aliasing pointers
       | to non-char types can trigger ubsan errors. With rep movsb it's a
       | good idea to check cpuid for erms support. In that case it'll be
       | fastest for bigger moves but is still slower for small moves. See
       | the chart at https://justine.lol/cosmopolitan/index.html which
       | compares various methods. Also take into consideration that if
       | you call zpl_memcpy() the compiler doesn't know that's memcpy()
       | so it can't perform some of its inlining magic at the call site.
       | So if you want things like null propagation it might be better to
       | do that as a macro.
       | 
       | Regarding array.c I implemented a bunch of similar routines
       | myself and eventually chose to not worry about capacity and just
       | call realloc every time. I'm not sure if the standard specifies
       | this, but I'm pretty sure every realloc implementation in
       | practice, under the hood, should track the capacity and grow it
       | at two power sizes. So even if you're just constantly appending
       | by one char the cost short amortize itself out to be cheap in the
       | long run.
        
         | zX41ZdbW wrote:
         | Testing performance of memcpy should be more exhaustive than
         | just running on single CPU:
         | https://github.com/ClickHouse/ClickHouse/issues/18583#issuec...
        
       | JediPig wrote:
       | is there any other similar libraries i should know about? frankly
       | the developer is right, I hate re-implementation of lists and
       | other crap in modern languages.
       | 
       | I have a complete crap kernel include file i use when I write
       | kernel modules. ( Though You will find me no longer publishing
       | source code. Client is moving to freebsd, after a linux kernel
       | bug that got labeled "WONT FIX" by linus & crew )
       | 
       | So client goes "WONT SUPPORT" on 5.x linux. Linux userland is a
       | damn mess.
        
       | Deukhoofd wrote:
       | So unrelated to the Zebra Programming Language?
        
       | [deleted]
        
       | [deleted]
        
       | wg0 wrote:
       | This is beautiful. I think I am going to toy around with it in a
       | project I have been dreaming about.
        
       | MaxBarraclough wrote:
       | > Most parts of the library are written in pure C99. There are
       | however, some additional components that require C11 to work
       | (notably in the Threading module). As long as you are using
       | minimal version (ZPL_NANO), and manually enable modules, the C99
       | support should be just fine.
       | 
       | I think it would be better to describe it as a C11 library. I
       | didn't know what to make of 'almost C99', which might refer to
       | limited use of compiler-specific features, for instance.
        
       | mhd wrote:
       | Is "Powerkit" some common term I'm missing here? At first I
       | thought this was related to some kind of Apple "Kit", written in
       | straight C instead of Objective-C/Swift.
        
         | up2isomorphism wrote:
         | I think that it is called "Powerkit" in a sense that it gives C
         | programmers some tools that make daily programming task easier.
        
       | [deleted]
        
       | szanni wrote:
       | This looks like a nice and concise library. Single header file,
       | many useful functions, and a usable license. The only thing I
       | really dislike are all of the typedefs.                 zpl_u64
       | zpl_crc64(void const *data, zpl_isize len);
       | 
       | Const correctness, good! But why is the size parameter signed?
       | Why not use size_t and uint64_t like the C stdlib?
        
         | messe wrote:
         | The zpl_u64 seems to be because they're trying to support older
         | versions of the MSVC compiler[1]. As for why they're using a
         | signed size parameter, I'm not really sure. One idiom they
         | appear to use often is[2]:                   for (...; x--;
         | y++)
         | 
         | where x is a size-type of some kind. They may be defaulting to
         | signed size types to avoid errors in case somebody decides to
         | change to above to:                   for (...; x-- >= 0; y++)
         | 
         | There's even a macro zpl_size_of:                   #define
         | zpl_size_of(x) (zpl_isize)(sizeof(x))
         | 
         | But the real weirdness is in the other macros:
         | #define cast(Type) (Type)
         | 
         | ...just why? And                   #define ZPL_MULTILINE(...)
         | #__VA_ARGS__
         | 
         | is supposed to be a way of having multiline literals in C. But,
         | everything inside the "..." has to be valid C tokens. It might
         | work as a string literal in many cases, but it's misleading at
         | best and broken at worst.
         | 
         | I'm not sure what the advantage of the following is vs. just
         | setting the bits using & and | which every C programmer should
         | already be familiar with:                   #define
         | ZPL_MASK_SET(var, set, mask) \         do {
         | \             if (set)                         \
         | (var) |= (mask);                 \             else
         | \             (var) &= ~(mask);                \         }
         | while (0)
         | 
         | There's surely no excuse for this:                   #define
         | zpl_global static        // Global variables
         | 
         | While a lot of the library looks useful, stuff like the above
         | makes it feel like it's written by somebody who knows C, but
         | doesn't feel fully comfortable writing it.
         | 
         | [1]:
         | https://github.com/zpl-c/zpl/blob/master/code/header/essenti...
         | 
         | [2]:
         | https://github.com/zpl-c/zpl/blob/27c80bd5807da5238777bfcba8...
        
           | up2isomorphism wrote:
           | These extra wrappers are most likely when library writer
           | trying to cover windows platform, which has almost never been
           | a good place for ANSI C programming.
        
           | keldaris wrote:
           | > There's surely no excuse for this
           | 
           | The "excuse" is greppability since static has three
           | completely different meanings in C and the desire to clearly
           | denote global variables is fairly common. The same reasoning
           | goes for the cast define as well.
           | 
           | Whether you find value in these small abuses of the
           | preprocessor depends on your coding habits, but I don't
           | really see much reason to criticize them. If the author finds
           | them helpful, what's the harm? There isn't much room for
           | confusion and they're not forced on the users of the library.
        
         | badsectoracula wrote:
         | From a quick look at the code it seems that zpl_isize is used
         | to represent indices, counts, etc and in those cases -1 is
         | often used as an "invalid" value with special meaning (e.g. in
         | the hashtable -1 is used as a "not found" index).
        
         | h_anna_h wrote:
         | A bit sad that they did not go for                   uint64_t
         | zpl_crc64(size_t len, const unsigned char data[len]);
        
           | colejohnson66 wrote:
           | Is that even portable?
        
             | kiwidrew wrote:
             | It's a C99 variable-length array declaration, so the syntax
             | is valid; but unfortunately it doesn't actually do anything
             | useful. The 'const unsigned char data[len]' declaration
             | just decays to 'const unsigned char *data' -- the first
             | level of array-ness is discarded.
             | 
             | [ there was a bit of discussion about this earlier in the
             | month: https://news.ycombinator.com/item?id=26349903 ]
        
               | h_anna_h wrote:
               | It is useful for static analysis, even the standard
               | people say that they will move into this kind of
               | declaration.
               | 
               | > 15. Application Programming Interfaces (APIs) should be
               | self-documenting when possible. In particular, the order
               | of parameters in function declarations should be arranged
               | such that the size of an array appears before the array.
               | The purpose is to allow Variable-Length Array (VLA)
               | notation to be used. This not only makes the code's
               | purpose clearer to human readers, but also makes static
               | analysis easier. Any new APIs added to the Standard
               | should take this into consideration.
               | 
               | from http://www.open-
               | std.org/jtc1/sc22/wg14/www/docs/n2086.htm
        
       ___________________________________________________________________
       (page generated 2021-03-20 23:01 UTC)