// // Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // stdlib -- // // Author : Peter A. Buhr // Created On : Thu Jan 28 17:12:35 2016 // Last Modified By : Peter A. Buhr // Last Modified On : Tue Apr 23 14:05:21 2024 // Update Count : 963 // #pragma once #include "bits/defs.hfa" // OPTIONAL_THREAD #include "bits/align.hfa" // libAlign #include "bits/random.hfa" // prng #include #include #include // *alloc, strto*, ato* #include // Reduce includes by explicitly defining these routines. extern "C" { void * memalign( size_t alignment, size_t size ); // malloc.h void * pvalloc( size_t size ); // malloc.h void * memset( void * dest, int fill, size_t size ); // string.h void * memcpy( void * dest, const void * src, size_t size ); // string.h } // extern "C" //--------------------------------------- #ifndef EXIT_FAILURE #define EXIT_FAILURE 1 // failing exit status #define EXIT_SUCCESS 0 // successful exit status #endif // ! EXIT_FAILURE //--------------------------------------- #include "common.hfa" //--------------------------------------- static inline forall( T & | sized(T) ) { // CFA safe equivalents, i.e., implicit size specification, eliminate return-type cast T * malloc( void ) { if ( _Alignof(T) <= libAlign() ) return (T *)malloc( sizeof(T) ); // C allocation else return (T *)memalign( _Alignof(T), sizeof(T) ); } // malloc T * aalloc( size_t dim ) { if ( _Alignof(T) <= libAlign() ) return (T *)aalloc( dim, sizeof(T) ); // C allocation else return (T *)amemalign( _Alignof(T), dim, sizeof(T) ); } // aalloc T * calloc( size_t dim ) { if ( _Alignof(T) <= libAlign() ) return (T *)calloc( dim, sizeof(T) ); // C allocation else return (T *)cmemalign( _Alignof(T), dim, sizeof(T) ); } // calloc T * resize( T * ptr, size_t size ) { if ( _Alignof(T) <= libAlign() ) return (T *)resize( (void *)ptr, size ); // C resize else return (T *)resize( (void *)ptr, _Alignof(T), size ); // CFA resize } // resize T * resize( T * ptr, size_t alignment, size_t size ) { return (T *)resize( (void *)ptr, alignment, size ); // CFA resize } // resize T * realloc( T * ptr, size_t size ) { // CFA realloc if ( _Alignof(T) <= libAlign() ) return (T *)realloc( (void *)ptr, size ); // C realloc else return (T *)realloc( (void *)ptr, _Alignof(T), size ); // CFA realloc } // realloc T * realloc( T * ptr, size_t alignment, size_t size ) { return (T *)realloc( (void *)ptr, alignment, size ); // CFA realloc } // realloc T * reallocarray( T * ptr, size_t dim ) { // CFA reallocarray if ( _Alignof(T) <= libAlign() ) return (T *)reallocarray( (void *)ptr, dim, sizeof(T) ); // C reallocarray else return (T *)reallocarray( (void *)ptr, _Alignof(T), dim ); // CFA reallocarray } // realloc T * reallocarray( T * ptr, size_t alignment, size_t dim ) { return (T *)reallocarray( (void *)ptr, alignment, dim ); // CFA reallocarray } // realloc T * memalign( size_t align ) { return (T *)memalign( align, sizeof(T) ); // C memalign } // memalign T * amemalign( size_t align, size_t dim ) { return (T *)amemalign( align, dim, sizeof(T) ); // CFA amemalign } // amemalign T * cmemalign( size_t align, size_t dim ) { return (T *)cmemalign( align, dim, sizeof(T) ); // CFA cmemalign } // cmemalign T * aligned_alloc( size_t align ) { return (T *)aligned_alloc( align, sizeof(T) ); // C aligned_alloc } // aligned_alloc int posix_memalign( T ** ptr, size_t align ) { return posix_memalign( (void **)ptr, align, sizeof(T) ); // C posix_memalign } // posix_memalign T * valloc( void ) { return (T *)valloc( sizeof(T) ); // C valloc } // valloc T * pvalloc( void ) { return (T *)pvalloc( sizeof(T) ); // C pvalloc } // pvalloc } // distribution /* FIX ME : fix alloc interface after Ticker Number 214 is resolved, define and add union to S_fill. Then, modify postfix-fill functions to support T * with nmemb, char, and T object of any size. Finally, change alloc_internal. Or, just follow the instructions below for that. 1. Replace the current forall-block that contains defintions of S_fill and S_realloc with following: forall( T & | sized(T) ) { union U_fill { char c; T * a; T t; }; struct S_fill { char tag; U_fill(T) fill; }; struct S_realloc { inline T *; }; } 2. Replace all current postfix-fill functions with following for updated S_fill: S_fill(T) ?`fill( char a ) { S_fill(T) ret = {'c'}; ret.fill.c = a; return ret; } S_fill(T) ?`fill( T a ) { S_fill(T) ret = {'t'}; memcpy(&ret.fill.t, &a, sizeof(T)); return ret; } S_fill(T) ?`fill( T a[], size_t nmemb ) { S_fill(T) ret = {'a', nmemb}; ret.fill.a = a; return ret; } 3. Replace the alloc_internal$ function which is outside ttype forall-block with following function: T * alloc_internal$( void * Resize, T * Realloc, size_t Align, size_t Dim, S_fill(T) Fill) { T * ptr = NULL; size_t size = sizeof(T); size_t copy_end = 0; if(Resize) { ptr = (T*) (void *) resize( (int *)Resize, Align, Dim * size ); } else if (Realloc) { if (Fill.tag != '0') copy_end = min(malloc_size( Realloc ), Dim * size); ptr = (T*) (void *) realloc( (int *)Realloc, Align, Dim * size ); } else { ptr = (T*) (void *) memalign( Align, Dim * size ); } if(Fill.tag == 'c') { memset( (char *)ptr + copy_end, (int)Fill.fill.c, Dim * size - copy_end ); } else if(Fill.tag == 't') { for ( int i = copy_end; i <= Dim * size - size ; i += size ) { memcpy( (char *)ptr + i, &Fill.fill.t, size ); } } else if(Fill.tag == 'a') { memcpy( (char *)ptr + copy_end, Fill.fill.a, min(Dim * size - copy_end, size * Fill.nmemb) ); } return ptr; } // alloc_internal$ */ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmaybe-uninitialized" #pragma GCC diagnostic ignored "-Wuninitialized" struct T_align { size_t align; }; struct T_resize { void * addr; }; struct T_realloc { void * addr; }; forall( T & ) struct T_fill { // 'N' => no fill, 'c' => fill with character c, 'a' => fill first N array elements from another array, // 'A' => fill all array elements from another array, 'T' => fill using a T value. char tag; size_t nelem; // number of elements copied from "at" (used with tag 'a') // union { char c; T * at; char t[64]; // T t; // }; }; #pragma GCC diagnostic pop static inline { T_align ?`align( size_t a ) { return (T_align){ a }; } T_resize ?`resize( void * a ) { return (T_resize){ a }; } T_realloc ?`realloc( void * a ) { return (T_realloc){ a }; } } static inline forall( T & | sized(T) ) { T_fill(T) ?`fill( char c ) { return (T_fill(T)){ 'c', 0, c }; } T_fill(T) ?`fill( T t ) { T_fill(T) ret = { 'T' }; size_t size = sizeof(T); if ( size > sizeof(ret.t) ) { abort( "ERROR: const object of size greater than 50 bytes given for dynamic memory fill\n" ); } // if memcpy( &ret.t, &t, size ); return ret; } T_fill(T) ?`fill( T a[] ) { return (T_fill(T)){ 'A', 0, '\0', a }; } // FIX ME: remove this once ticket 214 is resolved T_fill(T) ?`fill( T a[], size_t nelem ) { return (T_fill(T)){ 'a', nelem * sizeof(T), '\0', a }; } // private interface T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill ) { T * ptr; size_t tsize = sizeof(T); size_t copy_end = 0; if ( Resize.addr ) { ptr = (T *)(void *)resize( Resize.addr, Align, Dim * tsize ); } else if ( Realloc.addr ) { if ( Fill.tag != 'N' ) copy_end = min(malloc_size( Realloc.addr ), Dim * tsize ); ptr = (T *)(void *)realloc( Realloc.addr, Align, Dim * tsize ); } else { ptr = (T *)(void *)memalign( Align, Dim * tsize ); } // if if ( Fill.tag == 'c' ) { memset( (char *)ptr + copy_end, (int)Fill.c, Dim * tsize - copy_end ); } else if ( Fill.tag == 'T' ) { for ( i; copy_end ~ Dim * tsize ~ tsize ) { assert( tsize <= sizeof(Fill.t) ); memcpy( (char *)ptr + i, &Fill.t, tsize ); } // for } else if ( Fill.tag == 'a' ) { memcpy( (char *)ptr + copy_end, Fill.at, min( Dim * tsize - copy_end, Fill.nelem ) ); } else if ( Fill.tag == 'A' ) { memcpy( (char *)ptr + copy_end, Fill.at, Dim * tsize ); } // if return ptr; } // alloc_internal$ // Dim is a fixed (optional first) parameter, and hence is not set using a postfix function. A dummy parameter is // being overwritten by the postfix argument in the ttype. forall( List ... | { T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) Fill, List ); } ) { // middle interface T * alloc_internal$( size_t Dim, T_resize dummy, T_realloc Realloc, size_t Align, T_fill(T) Fill, T_resize Resize, List rest ) { return alloc_internal$( Dim, Resize, (T_realloc){0p}, Align, Fill, rest ); } T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc dummy, size_t Align, T_fill(T) Fill, T_realloc Realloc, List rest ) { return alloc_internal$( Dim, (T_resize){0p}, Realloc, Align, Fill, rest ); } T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t dummy, T_fill(T) Fill, T_align Align, List rest ) { return alloc_internal$( Dim, Resize, Realloc, Align.align, Fill, rest ); } T * alloc_internal$( size_t Dim, T_resize Resize, T_realloc Realloc, size_t Align, T_fill(T) dummy, T_fill(T) Fill, List rest ) { return alloc_internal$( Dim, Resize, Realloc, Align, Fill, rest ); } // public interface T * alloc( List rest ) { return alloc_internal$( (size_t)1, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest ); } T * alloc( size_t Dim, List rest ) { return alloc_internal$( Dim, (T_resize){0p}, (T_realloc){0p}, (_Alignof(T) > libAlign() ? _Alignof(T) : libAlign()), (T_fill(T)){'N'}, rest ); } } // distribution List } // distribution T static inline forall( T & | sized(T) ) { // CFA safe initialization/copy, i.e., implicit size specification, non-array types T * memset( T * dest, char fill ) { // all combinations of pointer/reference return (T *)memset( dest, fill, sizeof(T) ); // C memset } // memset T * memset( T & dest, char fill ) { return (T *)memset( &dest, fill, sizeof(T) ); // C memset } // memset T * memcpy( T * dest, const T * src ) { // all combinations of pointer/reference return (T *)memcpy( dest, src, sizeof(T) ); // C memcpy } // memcpy T * memcpy( T & dest, const T & src ) { return (T *)memcpy( &dest, &src, sizeof(T) ); // C memcpy } // memcpy T * memcpy( T * dest, const T & src ) { return (T *)memcpy( dest, &src, sizeof(T) ); // C memcpy } // memcpy T * memcpy( T & dest, const T * src ) { return (T *)memcpy( &dest, src, sizeof(T) ); // C memcpy } // memcpy // CFA safe initialization/copy, i.e., implicit size specification, array types T * amemset( T dest[], char fill, size_t dim ) { return (T *)(void *)memset( dest, fill, dim * sizeof(T) ); // C memset } // amemset T * amemcpy( T dest[], const T src[], size_t dim ) { return (T *)(void *)memcpy( dest, src, dim * sizeof(T) ); // C memcpy } // amemcpy } // distribution // CFA deallocation for multiple objects static inline forall( T & ) void free( T * ptr ) { free( (void *)ptr ); // C free } // free static inline forall( T &, List ... | { void free( List ); } ) void free( T * ptr, List rest ) { free( ptr ); free( rest ); } // free // CFA allocation/deallocation and constructor/destructor, non-array types static inline forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * new( Parms p ) { return &(*(T *)malloc()){ p }; // run constructor } // new static inline forall( T & | { void ^?{}( T & ); } ) void delete( T * ptr ) { // special case for 0-sized object => always call destructor if ( ptr || sizeof(ptr) == 0 ) { // ignore null but not 0-sized objects ^(*ptr){}; // run destructor } // if free( ptr ); // always call free } // delete static inline forall( T &, List ... | { void ^?{}( T & ); void delete( List ); } ) void delete( T * ptr, List rest ) { delete( ptr ); delete( rest ); } // delete // CFA allocation/deallocation and constructor/destructor, array types forall( T & | sized(T), Parms ... | { void ?{}( T &, Parms ); } ) T * anew( size_t dim, Parms p ); forall( T & | sized(T) | { void ^?{}( T & ); } ) void adelete( T arr[] ); forall( T & | sized(T) | { void ^?{}( T & ); }, List ... | { void adelete( List ); } ) void adelete( T arr[], List rest ); //--------------------------------------- // Check if all string characters are a specific kind, e.g., checkif( s, isblank ) bool checkif( const char s[], int (* kind)( int ) ); bool checkif( const char s[], int (* kind)( int, locale_t ), locale_t locale ); //--------------------------------------- static inline { int strto( const char sptr[], char * eptr[], int base ) { return (int)strtol( sptr, eptr, base ); } unsigned int strto( const char sptr[], char * eptr[], int base ) { return (unsigned int)strtoul( sptr, eptr, base ); } long int strto( const char sptr[], char * eptr[], int base ) { return strtol( sptr, eptr, base ); } unsigned long int strto( const char sptr[], char * eptr[], int base ) { return strtoul( sptr, eptr, base ); } long long int strto( const char sptr[], char * eptr[], int base ) { return strtoll( sptr, eptr, base ); } unsigned long long int strto( const char sptr[], char * eptr[], int base ) { return strtoull( sptr, eptr, base ); } float strto( const char sptr[], char * eptr[] ) { return strtof( sptr, eptr ); } double strto( const char sptr[], char * eptr[] ) { return strtod( sptr, eptr ); } long double strto( const char sptr[], char * eptr[] ) { return strtold( sptr, eptr ); } } // distribution float _Complex strto( const char sptr[], char * eptr[] ); double _Complex strto( const char sptr[], char * eptr[] ); long double _Complex strto( const char sptr[], char * eptr[] ); ExceptionDecl( out_of_range ); ExceptionDecl( invalid_argument ); forall( T | { T strto( const char sptr[], char * eptr[], int ); } ) T convert( const char sptr[] ); // integrals forall( T | { T strto( const char sptr[], char * eptr[] ); } ) T convert( const char sptr[] ); // floating-point (no base) static inline { int ato( const char sptr[] ) { return (int)strtol( sptr, 0p, 10 ); } unsigned int ato( const char sptr[] ) { return (unsigned int)strtoul( sptr, 0p, 10 ); } long int ato( const char sptr[] ) { return strtol( sptr, 0p, 10 ); } unsigned long int ato( const char sptr[] ) { return strtoul( sptr, 0p, 10 ); } long long int ato( const char sptr[] ) { return strtoll( sptr, 0p, 10 ); } unsigned long long int ato( const char sptr[] ) { return strtoull( sptr, 0p, 10 ); } float ato( const char sptr[] ) { return strtof( sptr, 0p ); } double ato( const char sptr[] ) { return strtod( sptr, 0p ); } long double ato( const char sptr[] ) { return strtold( sptr, 0p ); } float _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } long double _Complex ato( const char sptr[] ) { return strto( sptr, 0p ); } } // distribution //--------------------------------------- forall( E | { int ?