Commit abb4e670 authored by Thibault Allançon's avatar Thibault Allançon

Merge branch 'ta/brick-update' into ta/bitstate

Update bricks library to latest 4.4.2 version.
parents ef515e22 b8fc9719
Pipeline #18075 failed with stage
in 30 minutes and 26 seconds
......@@ -22,8 +22,16 @@
AUTOMAKE_OPTIONS = subdir-objects
nobase_include_HEADERS= bricks/brick-assert bricks/brick-bitlevel \
bricks/brick-hash bricks/brick-hashset bricks/brick-shmem \
nobase_include_HEADERS= \
bricks/brick-assert \
bricks/brick-bitlevel \
bricks/brick-hash \
bricks/brick-hashset \
bricks/brick-min \
bricks/brick-ptr \
bricks/brick-shmem \
bricks/brick-string \
bricks/brick-trace \
bricks/brick-types
......
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/*
* Various assert macros based on C++ exceptions and their support code.
*/
/*
* (c) 2006-2016 Petr Ročkai <code@fixp.eu>
* (c) 2006-2019 Petr Ročkai <code@fixp.eu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
......@@ -20,214 +16,185 @@
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <exception>
#include <string>
#include <sstream>
#pragma once
#ifndef TEST
#define TEST(n) void n()
#define TEST_FAILING(n) void n()
#include "brick-trace"
#include <unistd.h>
#ifdef __divine__
#include <sys/fault.h>
#endif
#ifndef NDEBUG
/* This file provides an assortment of assertion macros which provide
* additional information about the circumstances of assertion failures, for
* instance ASSERT_EQ will print both the source code statement and the actual
* values that unexpectedly compared inequal.
*
* The assertion failure mechanism is currently implemented as an exception,
* with the intention to be catchable, if the user so desires. This can be used
* to e.g. print additional context information relevant to the failure, as the
* stack is being unwound.
*
* Additionally, this files provides a stub version of the TEST() macro, a real
* version of which is implemented in brick-unittest. This allows unit test
* suites to be included in header files along with the code that they test
* (without the testcases being actually registered or instantiatied unless the
* unit testsuite is being built). */
#ifndef TEST
#define TEST(n) template< bool > void n()
#endif
#define BRICK_SHARP_FIRST(x, ...) #x
#define ASSERT(...) ::brick::_assert::assert_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( BRICK_SHARP_FIRST( __VA_ARGS__, ignored ) ) ), __VA_ARGS__ )
#define ASSERT_PRED(p, x) ::brick::_assert::assert_pred_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( #p "( " #x " )" ) ), x, p( x ) )
#define ASSERT_EQ(x, y) ::brick::_assert::assert_eq_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( #x " == " #y ) ), x, y )
#define ASSERT_LT(x, y) ::brick::_assert::assert_lt_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( #x " < " #y ) ), x, y )
#define ASSERT_LEQ(x, y) ::brick::_assert::assert_leq_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( #x " <= " #y ) ), x, y )
#define ASSERT_NEQ(x, y) ::brick::_assert::assert_neq_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( #x " != " #y ) ), x, y )
#define ASSERT_EQ_IDX(i, x, y) ::brick::_assert::assert_eq_fn( \
BRICK_LOCWRAP( BRICK_LOCATION_I( #x " == " #y, i ) ), x, y )
#define BRICK_ASSERT(t,l,...) ::brq::assert_ ## t ## _fn( BRICK_LOCATION( l ), __VA_ARGS__ )
#else
#ifdef NDEBUG
#define ASSERT(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_PRED(p, x) static_cast< decltype(p, x, void(0)) >(0)
#define ASSERT_EQ(x, y) static_cast< decltype(x, y, void(0)) >(0)
#define ASSERT_LEQ(x, y) static_cast< decltype(x, y, void(0)) >(0)
#define ASSERT_LT(x, y) static_cast< decltype(x, y, void(0)) >(0)
#define ASSERT_NEQ(x, y) static_cast< decltype(x, y, void(0)) >(0)
#define ASSERT_EQ_IDX(i, x, y) static_cast< decltype(i, x, y, void(0)) >(0)
#endif
#define ASSERT(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_PRED(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_EQ(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_LEQ(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_LT(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
#define ASSERT_NEQ(...) static_cast< decltype(__VA_ARGS__, void(0)) >(0)
/* you must #include <brick-string> to use ASSERT_UNREACHABLE_F */
#define UNREACHABLE_F(...) ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( brick::string::fmtf(__VA_ARGS__) ) ) )
#define UNREACHABLE(...) ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( ::brick::_assert::fmt( __VA_ARGS__ ) ) ) )
#define UNREACHABLE_() ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( "an unreachable location" ) ) )
#define NOT_IMPLEMENTED() ::brick::_assert::assert_die_fn( \
BRICK_LOCWRAP( BRICK_LOCATION( "a missing implementation" ) ) )
#ifdef _MSC_VER
#define UNUSED
#define noexcept
#else
#define UNUSED __attribute__((unused))
#endif
#ifndef BRICK_ASSERT_H
#define BRICK_ASSERT_H
#define BRICK_ASSERT_BIN(op, inv, x, ...) \
BRICK_ASSERT( bin, \
#x " " #op " " BRICK_SHARP_FIRST( __VA_ARGS__, ignored ), \
[]( const auto &a, const auto &b ) { return a op b; }, \
#op, #inv, x, __VA_ARGS__ )
#define ASSERT(...) BRICK_ASSERT( bool, BRICK_SHARP_FIRST( __VA_ARGS__, ignored ), __VA_ARGS__ )
#define ASSERT_P(p, x) BRICK_ASSERT( pred, #p "( " #x " )", x, p( x ) )
#define ASSERT_EQ(...) BRICK_ASSERT_BIN( ==, !=, __VA_ARGS__ )
#define ASSERT_LT(...) BRICK_ASSERT_BIN( <, >=, __VA_ARGS__ )
#define ASSERT_LEQ(...) BRICK_ASSERT_BIN( <=, >, __VA_ARGS__ )
#define ASSERT_NEQ(...) BRICK_ASSERT_BIN( !=, ==, __VA_ARGS__ )
namespace brick {
namespace _assert {
#endif
/* you must #include <brick-string> to use UNREACHABLE_F */
#define UNREACHABLE(...) BRICK_ASSERT( die, "", __VA_ARGS__ )
#define NOT_IMPLEMENTED() BRICK_ASSERT( die, "", "missing implementation" )
/* discard any number of parameters, taken as const references */
template< typename... X >
void unused( const X&... ) { }
#define BRICK_LOCATION(stmt) ::brq::trace_location{ __LINE__, __FILE__, stmt }
struct Location {
int line, iteration;
std::string file, stmt;
Location( const char *f, int l, std::string st, int iter = -1 )
: line( l ), iteration( iter ), file( f ), stmt( st )
namespace brq
{
struct assert_failed : string_builder
{
int slashes = 0;
for ( int i = 0; i < int( file.size() ); ++i )
if ( file[i] == '/' )
++ slashes;
struct fail_ref
{
assert_failed &ref;
explicit fail_ref( assert_failed &f ) : ref( f ) {}
};
while ( slashes >= 3 )
template< typename X >
friend inline auto operator<<( fail_ref f, const X &x )
-> decltype( std::declval< string_builder & >() << x, f.ref )
{
file = std::string( file, file.find( "/" ) + 1, std::string::npos );
-- slashes;
f.ref << x;
return f.ref;
}
if ( f != file )
file = ".../" + file;
}
};
#define BRICK_LOCATION(stmt) ::brick::_assert::Location( __FILE__, __LINE__, stmt )
#define BRICK_LOCATION_I(stmt, i) ::brick::_assert::Location( __FILE__, __LINE__, stmt, i )
assert_failed( const trace_location &l, const char *expected = "expected" )
{
std::string_view file( l._file );
int slashes = 0;
for ( auto c : file )
if ( c == '/' )
++ slashes;
while ( slashes >= 3 )
{
file.remove_prefix( file.find( "/" ) + 1 );
-- slashes;
}
if ( file != l._file )
(*this) << ".../";
(*this) << file << ": " << l.line;
(*this) << ":\n " << expected << " " << l.statement();
}
// lazy location construction in C++11
#if __cplusplus >= 201103L
#define BRICK_LOCWRAP(x) [&]{ return (x); }
#define BRICK_LOCUNWRAP(x) (x)()
#else
#define BRICK_LOCWRAP(x) (x)
#define BRICK_LOCUNWRAP(x) (x)
#ifdef BRICKS_NOTHROW_ASSERTS
assert_failed( assert_failed &&o )
{
::write( 2, o.buffer(), o._offset );
abort();
}
#endif
struct AssertFailed : std::exception
{
std::string str;
const char *what() const noexcept { return buffer(); }
};
template< typename X >
friend inline AssertFailed &operator<<( AssertFailed &f, X x )
[[noreturn]] static inline void assert_signal( assert_failed &err )
{
std::stringstream str;
str << x;
f.str += str.str();
return f;
#if defined(__divine__)
if ( err.truncated() )
__vm_cancel();
__dios_fault( _VM_F_Assert, err.what() );
__builtin_trap();
#else
throw std::move( err );
#endif
}
AssertFailed( Location l, const char *expected = "expected" )
template< typename X, typename... Y >
void assert_bool_fn( const trace_location &l, const X &x, const Y & ... y )
{
(*this) << l.file << ": " << l.line;
if ( l.iteration != -1 )
(*this) << " (iteration " << l.iteration << ")";
(*this) << ":\n " << expected << " " << l.stmt;
if ( x )
return;
assert_failed f( l );
format_args< true >( " ", f, y... );
assert_signal( f );
trace_fn< true >( 4, l, "assert:", l._statement, y... );
}
const char *what() const noexcept override { return str.c_str(); }
};
static inline void format( AssertFailed & ) {}
template< typename X, typename... Y >
void format( AssertFailed &f, X x, Y... y )
{
f << x;
format( f, y... );
}
template< typename... T >
__attribute__((noreturn))
void assert_die_fn( const trace_location &l, const T & ... args )
{
assert_failed f( l, "unreachable executed:" );
format_args< true >( " ", f, args... );
assert_signal( f );
}
template< typename Location, typename X, typename... Y >
void assert_fn( Location l, X x, Y... y )
{
if ( x )
return;
AssertFailed f( BRICK_LOCUNWRAP( l ) );
format( f, y... );
throw f;
}
template< typename Op, typename A, typename B, typename... T >
void assert_bin_fn( const trace_location &l, Op op, std::string_view op_str, std::string_view inv,
const A &a, const B &b, const T & ... args )
{
bool pass;
template< typename Location >
inline void assert_die_fn( Location l ) __attribute__((noreturn));
if constexpr ( std::is_integral_v< A > && std::is_integral_v< B > )
pass = op( static_cast< std::common_type_t< A, B > >( a ),
static_cast< std::common_type_t< A, B > >( b ) );
else
pass = !!op( a, b );
template< typename Location >
inline void assert_die_fn( Location l )
{
throw AssertFailed( BRICK_LOCUNWRAP( l ), "encountered" );
}
if ( !pass )
{
assert_failed f( l );
f << "\n but got " << a << " " << inv << " " << b << "\n";
format_args< true >( " ", f, args... );
assert_signal( f );
}
#define ASSERT_FN(name, op, inv) \
template< typename Location > \
void assert_ ## name ## _fn( Location l, int64_t x, int64_t y ) \
{ \
if ( !( x op y ) ) { \
AssertFailed f( BRICK_LOCUNWRAP( l ) ); \
f << "\n but got " \
<< x << " " #inv " " << y << "\n"; \
throw f; \
} \
} \
\
template< typename Location, typename X, typename Y > \
auto assert_ ## name ## _fn( Location l, X x, Y y ) \
-> typename std::enable_if< \
!std::is_integral< X >::value || \
!std::is_integral< Y >::value >::type \
{ \
if ( !( x op y ) ) { \
AssertFailed f( BRICK_LOCUNWRAP( l ) ); \
f << "\n but got " \
<< x << " " #inv " " << y << "\n"; \
throw f; \
} \
trace_fn< true >( 4, l, "assert:", l._statement, "[", a, op_str, b, "]", args... );
}
ASSERT_FN(eq, ==, !=)
ASSERT_FN(leq, <=, >)
ASSERT_FN(lt, <, >=)
template< typename Location, typename X >
void assert_pred_fn( Location l, X x, bool p )
{
if ( !p ) {
AssertFailed f( BRICK_LOCUNWRAP( l ) );
f << "\n but got x = " << x << "\n";
throw f;
template< typename X >
__boring void assert_pred_fn( const trace_location &l, X x, bool p )
{
if ( !p )
{
assert_failed f( l );
f << "\n but got x = " << x << "\n";
assert_signal( f );
}
}
}
template< typename Location, typename X, typename Y >
void assert_neq_fn( Location l, X x, Y y )
{
if ( x != y )
return;
AssertFailed f( BRICK_LOCUNWRAP( l ) );
f << "\n but got "
<< x << " == " << y << "\n";
throw f;
}
inline std::string fmt( const char *str ) { return str; }
inline std::string fmt( std::string str ) { return str; }
// another overload of fmt is exported by brick-string and it allows more complex formating
}
}
#endif
// vim: syntax=cpp tabstop=4 shiftwidth=4 expandtab
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*-
/*
* (c) 2019 Petr Ročkai <code@fixp.eu>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#pragma once
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <string_view>
#include <charconv>
#ifndef __inline_opt
#define __inline_opt
#endif
namespace brq
{
template< typename B, typename T, typename = void > struct is_printable : std::false_type {};
template< typename B, typename T >
struct is_printable< B, T, decltype( std::declval< B & >() << std::declval< const T & >(),
void( 0 ) ) > : std::true_type {};
template< typename B, typename T >
constexpr bool is_printable_v = is_printable< B, T >::value;
/* A simple string builder, similar to std::stringstream but much lighter.
* Only works with 8-bit characters (i.e. no wchar_t or char32_t). Provides
* a basic selection of formatting operators. To provide formatting
* operators for custom types, the following idiom may be useful to use the
* same definition for std::ostream and for string_builder (also works for
* friend-style definitions):
*
* template< typename stream >
* auto operator<<( stream &o, my_type t ) -> decltype( o << "" )
* {
* // ...
* }
*
* Besides accepting values to format, string_builder also understands
* std::dec and std::hex IO manipulators. */
struct string_builder
{
char *_buffer = nullptr;
int32_t _capacity:30, _offset:30;
bool _hex:1, _oom:1;
string_builder( const string_builder & ) = delete;
string_builder( string_builder &&o )
: _buffer( o._buffer ), _capacity( o._capacity ), _offset( o._offset ),
_hex( o._hex ), _oom( o._oom )
{
o._buffer = nullptr;
o._capacity = 0;
o._offset = 0;
}
string_builder() noexcept : _capacity( 0 ), _offset( 0 ), _hex( false ), _oom( false ) {}
~string_builder() noexcept { std::free( _buffer ); }
char *pointer() noexcept { return _buffer + _offset; }
char *buffer_end() noexcept { return _buffer + _capacity - 1; }
const char *buffer() const noexcept { return _buffer ? _buffer : ""; }
std::string_view data() const noexcept { return std::string_view( _buffer, _offset ); }
operator std::string_view() const noexcept { return data(); }
int size() const noexcept { return _offset; }
bool truncated() const noexcept { return _oom; }
void kill() { clear(); _oom = true; }
string_builder &hex( bool h = true ) { _hex = h; return *this; }
string_builder &dec() { _hex = false; return *this; }
void clear()
{
std::free( _buffer );
_buffer = nullptr;
_capacity = _offset = 0;
_hex = _oom = false;
}
bool _make_space( int sz ) noexcept
{
if ( _oom )
return false;
if ( _offset + sz < _capacity )
return true;
int new_capacity = _capacity + std::max( _capacity / 2, sz + 1 );
void *mem = std::realloc( _buffer, new_capacity );
if ( mem )
{
_buffer = static_cast< char * >( mem );
_capacity = new_capacity;
}
else
_oom = true;
return !_oom;
}
string_builder &operator<<( std::string_view str ) noexcept
{
if ( !_make_space( str.size() ) ) return *this;
std::copy( str.begin(), str.end(), pointer() );
_offset += str.size();
_buffer[ _offset ] = 0;
return *this;
}
string_builder &operator<<( std::u32string_view us ) noexcept
{
while ( !us.empty() )
{
if ( !_make_space( 4 ) ) return *this;
uint32_t wc = us.front();
if ( ( wc & 0xFFFFF800 ) == 0x00D800 || wc > 0x10FFFF )
continue; /* skip the character */
if ( wc < 0x000080 )
{
_buffer[ _offset++ ] = static_cast< uint8_t >( wc );
}
else if ( wc < 0x000800 )
{
_buffer[ _offset++ ] = static_cast< uint8_t >( 0xC0 | ( wc >> 6 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( wc & 0x03F ) );
}
else if ( wc < 0x010000 )
{
_buffer[ _offset++ ] = static_cast< uint8_t >( 0xE0 | ( wc >> 12 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( ( wc & 0x0FC0 ) >> 6 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( wc & 0x003F ) );
}
else // if (wc < 0x110000)
{
_buffer[ _offset++ ] = static_cast< uint8_t >( 0xF0 | ( wc >> 18 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( ( wc & 0x03F000 ) >> 12 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( ( wc & 0x000FC0 ) >> 6 ) );
_buffer[ _offset++ ] = static_cast< uint8_t >( 0x80 | ( wc & 0x00003F ) );
}
us.remove_prefix( 1 );
}
return *this;
}
string_builder &operator<<( char c ) noexcept
{
*this << int( c );
if ( std::isprint( c ) )
{
if ( !_make_space( 3 ) ) return *this;
_buffer[ _offset++ ] = '\'';
_buffer[ _offset++ ] = c;
_buffer[ _offset++ ] = '\'';
_buffer[ _offset ] = 0;
}
return *this;
}
string_builder &operator<<( const void *ptr ) noexcept
{
auto was_hex = _hex;
_hex = true;
(*this) << uintptr_t( ptr );
_hex = was_hex;
return *this;
}
string_builder &operator<<( const char *str ) noexcept
{
return (*this) << ( str ? std::string_view( str ) : "<nullptr>" );
}
// FIX HERE: fix recursive template depth exceeded (from brick-hashset)
/*template< typename C >
auto operator<<( const C &c ) noexcept
-> std::enable_if_t< !std::is_convertible_v< C, std::string_view > &&
!std::is_convertible_v< C, std::u32string_view >,
decltype( c.has_value(), *this << *c ) >
{
if ( c.has_value() )
return *this << "[ " << *c << " ]";
else
return *this << "<null>";
}*/
template< typename C >
auto operator<<( const C &c ) noexcept
-> std::enable_if_t< !std::is_convertible_v< C, std::string_view > &&
!std::is_convertible_v< C, std::u32string_view > &&
is_printable_v< string_builder, decltype( *c.begin() ) > &&
is_printable_v< string_builder, decltype( *c.end() ) >,
string_builder & >
{
bool first = true;
*this << "[";
for ( const auto &e : c )
*this << ( first ? first = false, " " : ", " ) << e;
*this << ( first ? "]" : " ]" );
return *this;
}
template< typename P >
auto operator<<( const P &p ) noexcept -> decltype( *this << p.first << p.second )
{
return *this << "[" << p.first << ", " << p.second << "]";
}
template< typename F >
auto operator<<( const F &f ) noexcept
-> decltype( f( *this ), *this )
{
return f( *this ), *this;
}
// FIX HERE: fix recursive template depth exceeded (from brick-hashset)
/*template< typename V >
auto operator<<( const V &val ) noexcept
-> decltype( std::to_chars( _buffer, _buffer, val ), *this )
{
int cap = 16;
std::to_chars_result result;
do {
if ( !_make_space( cap ) ) return *this;
if constexpr ( std::is_integral< V >::value )
result = std::to_chars( pointer(), buffer_end(), val, _hex ? 16 : 10 );
else
result = std::to_chars( pointer(), buffer_end(), val );
cap *= 2;
} while ( result.ec == std::errc::value_too_large );
_offset = result.ptr - _buffer;
_buffer[ _offset ] = 0;
return *this;
}*/
};