mirror of
https://github.com/Alcaro/Flips.git
synced 2026-09-07 18:16:06 -05:00
Update Arlib
This commit is contained in:
@@ -113,11 +113,6 @@ endif
|
||||
|
||||
OUTNAME = $(PROGRAM)$(EXESUFFIX)
|
||||
|
||||
ifneq ($(SELFTEST),)
|
||||
CONF_CFLAGS += -DARLIB_TEST -Dmain=not_quite_main
|
||||
OBJNAME += -test
|
||||
endif
|
||||
|
||||
#OBJMANGLE(rule,sources) - takes C/C++ source files and returns the mangled name under the specified rule
|
||||
OBJMANGLE = $(patsubst %,obj/$1___$(OBJNAME)___%.o,$(subst /,__,$2))
|
||||
#SOURCENAME(obj) - takes a .o file, returned from OBJMANGLE, and returns the corresponding source file
|
||||
@@ -135,10 +130,23 @@ obj/%.c.o: $$(call SOURCENAME,$$@) | obj
|
||||
obj/%.cpp.o: $$(call SOURCENAME,$$@) | obj
|
||||
$(CXX) $(TRUE_CXXFLAGS) $(CFLAGS_$(call DOMAINNAME,$@)) -c $< -o $@
|
||||
|
||||
SOURCES += *.cpp arlib/*.cpp
|
||||
SOURCES += *.cpp
|
||||
SOURCES_ARLIB := arlib/*.cpp
|
||||
|
||||
ifneq ($(SELFTEST),)
|
||||
ifeq ($(ARLIB_MAIN),)
|
||||
CONF_CFLAGS += -DARLIB_TEST -Dmain=not_quite_main
|
||||
CFLAGS_ARLIB += -UARLIB_TEST -DARLIB_TESTRUNNER
|
||||
DOMAINS :=
|
||||
else
|
||||
SOURCES :=
|
||||
CFLAGS_ARLIB += -DARLIB_TEST -DARLIB_TESTRUNNER -DARLIB_TEST_ARLIB
|
||||
endif
|
||||
OBJNAME += -test
|
||||
endif
|
||||
|
||||
ifeq ($(ARGUI),1)
|
||||
SOURCES += arlib/gui/*.cpp
|
||||
SOURCES_ARLIB += arlib/gui/*.cpp
|
||||
ifeq ($(OS),windows)
|
||||
CONF_CFLAGS += -DARGUI_WINDOWS
|
||||
CONF_LFLAGS += -lgdi32 -lcomctl32 -lcomdlg32
|
||||
@@ -155,7 +163,7 @@ ifeq ($(AROPENGL),1)
|
||||
ifeq ($(ARGUI),0)
|
||||
$(error can't use OpenGL without the GUI)
|
||||
endif
|
||||
SOURCES += arlib/opengl/*.cpp
|
||||
SOURCES_ARLIB += arlib/opengl/*.cpp
|
||||
CONF_CFLAGS += -DARLIB_OPENGL
|
||||
ifeq ($(OS),linux)
|
||||
CONF_LFLAGS += -ldl
|
||||
@@ -166,7 +174,7 @@ ifeq ($(AROPENGL),1)
|
||||
endif
|
||||
|
||||
ifeq ($(ARTHREAD),1)
|
||||
SOURCES += arlib/thread/*.cpp
|
||||
SOURCES_ARLIB += arlib/thread/*.cpp
|
||||
CONF_CFLAGS += -DARLIB_THREAD
|
||||
ifeq ($(OS),linux)
|
||||
CONF_CFLAGS += -pthread
|
||||
@@ -175,7 +183,7 @@ ifeq ($(ARTHREAD),1)
|
||||
endif
|
||||
|
||||
ifeq ($(ARSANDBOX),1)
|
||||
SOURCES += arlib/sandbox/*.cpp
|
||||
SOURCES_ARLIB += arlib/sandbox/*.cpp
|
||||
CONF_CFLAGS += -DARLIB_SANDBOX
|
||||
#not true since the windows sandbox isn't a real sandbox
|
||||
#ifeq ($(OS),windows)
|
||||
@@ -187,12 +195,12 @@ ifeq ($(ARSANDBOX),1)
|
||||
endif
|
||||
|
||||
ifeq ($(ARWUTF),1)
|
||||
SOURCES += arlib/wutf/*.cpp
|
||||
SOURCES_ARLIB += arlib/wutf/*.cpp
|
||||
CONF_CFLAGS += -DARLIB_WUTF
|
||||
endif
|
||||
|
||||
ifeq ($(ARSOCKET),1)
|
||||
SOURCES += arlib/socket/*.cpp
|
||||
SOURCES_ARLIB += arlib/socket/*.cpp
|
||||
CONF_CFLAGS += -DARLIB_SOCKET
|
||||
|
||||
ifeq ($(OS),windows)
|
||||
@@ -219,7 +227,7 @@ ifeq ($(ARSOCKET),1)
|
||||
endif
|
||||
endif
|
||||
|
||||
SOURCES += arlib/deps/miniz.c
|
||||
SOURCES_ARLIB += arlib/deps/miniz.c
|
||||
|
||||
TRUE_CFLAGS = -std=c99 $(CCXXFLAGS) $(CFLAGS) $(CONF_CFLAGS)
|
||||
TRUE_CXXFLAGS =-std=c++11 -fno-rtti $(CCXXFLAGS) $(CXXFLAGS) $(CONF_CXXFLAGS)
|
||||
@@ -240,7 +248,7 @@ obj:
|
||||
mkdir obj
|
||||
|
||||
|
||||
DOMAINS += DEFAULT NOWARN
|
||||
DOMAINS += DEFAULT ARLIB NOWARN
|
||||
|
||||
OBJNAME := $(subst $(SPACE),,$(OBJNAME))
|
||||
SOURCES_DEFAULT := $(SOURCES)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "endian.h"
|
||||
#include "file.h"
|
||||
#include "function.h"
|
||||
#include "intsafe.h"
|
||||
#include "intwrap.h"
|
||||
#include "os.h"
|
||||
#include "serialize.h"
|
||||
|
||||
@@ -175,6 +175,15 @@ template<typename T> class array : public arrayvieww<T> {
|
||||
this->count=count;
|
||||
}
|
||||
|
||||
void resize_shrink_noinit(size_t count)
|
||||
{
|
||||
if (this->count <= count) return;
|
||||
size_t bufsize_pre = bitround(this->count);
|
||||
size_t bufsize_post = bitround(count);
|
||||
if (bufsize_pre != bufsize_post) this->items=realloc(this->items, sizeof(T)*bufsize_post);
|
||||
this->count=count;
|
||||
}
|
||||
|
||||
void resize_grow(size_t count)
|
||||
{
|
||||
size_t prevcount = this->count;
|
||||
@@ -253,6 +262,28 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
array<T> operator=(arrayview<T> other)
|
||||
{
|
||||
if (other.ptr() >= this->ptr() && other.ptr() < this->ptr()+this->size())
|
||||
{
|
||||
size_t start = other.ptr()-this->ptr();
|
||||
size_t len = other.size();
|
||||
|
||||
for (size_t i=0;i<start;i++) this->items[i].~T();
|
||||
memmove(this->ptr(), this->ptr()+start, sizeof(T)*len);
|
||||
for (size_t i=start+len;i<this->count;i++) this->items[i].~T();
|
||||
|
||||
resize_shrink_noinit(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i=0;i<this->count;i++) this->items[i].~T();
|
||||
free(this->items);
|
||||
clone(other);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~array()
|
||||
{
|
||||
for (size_t i=0;i<this->count;i++) this->items[i].~T();
|
||||
|
||||
@@ -16,8 +16,3 @@ uint32_t crc32_update(arrayview<uint8_t> data, uint32_t crc)
|
||||
}
|
||||
return ~crc;
|
||||
}
|
||||
|
||||
uint32_t crc32(arrayview<uint8_t> data)
|
||||
{
|
||||
return crc32_update(data, 0);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
#include "global.h"
|
||||
#include "array.h"
|
||||
|
||||
//uses 0xEDB88320 as generator polynomial
|
||||
uint32_t crc32(arrayview<uint8_t> data);
|
||||
//uses the standard 0xEDB88320 generator polynomial
|
||||
uint32_t crc32_update(arrayview<uint8_t> data, uint32_t crc);
|
||||
static inline uint32_t crc32(arrayview<uint8_t> data) { return crc32_update(data, 0); }
|
||||
|
||||
//calculates the 'inverse' crc32 of a buffer
|
||||
//given
|
||||
// a = crc32(buf1)
|
||||
// b = crc32_update(buf2, a) ( == crc32(buf1+buf2) )
|
||||
//then
|
||||
// crc32_cancel(buf2, b) == a
|
||||
uint32_t crc32_cancel(arrayview<uint8_t> data, uint32_t crc);
|
||||
|
||||
@@ -64,10 +64,9 @@ typedef void(*funcptr)();
|
||||
#define STR_(x) #x
|
||||
#define STR(x) STR_(x)
|
||||
|
||||
#define GCC_VER(ma,mi,pa) (ma*10000 + mi*100 + pa)
|
||||
#ifdef __GNUC__
|
||||
#define GCC_VERSION (__GNUC__ * 10000 \
|
||||
+ __GNUC_MINOR__ * 100 \
|
||||
+ __GNUC_PATCHLEVEL__)
|
||||
#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__)
|
||||
#define LIKELY(expr) __builtin_expect(!!(expr), true)
|
||||
#define UNLIKELY(expr) __builtin_expect(!!(expr), false)
|
||||
#else
|
||||
|
||||
36
arlib/intsafe.cpp
Normal file
36
arlib/intsafe.cpp
Normal file
@@ -0,0 +1,36 @@
|
||||
#define INTSAFE_SELFTEST
|
||||
#include "intsafe.h"
|
||||
#include "test.h"
|
||||
|
||||
#if 0 // apparently running 65536 iterations of anything under Valgrind takes a while
|
||||
#define TEST(t,op) \
|
||||
for (int a=0;a<256;a++) \
|
||||
for (int b=0;b<256;b++) \
|
||||
{ \
|
||||
int au = (t)a; \
|
||||
int bu = (t)b; \
|
||||
intsafe<t> as = au; \
|
||||
intsafe<t> bs = bu; \
|
||||
if (as.valid() && bs.valid()) \
|
||||
{ \
|
||||
intsafe<t> cs1 = (1 op 8 == 256/*if op == <<*/ && b>7 ? 999 : au op bu); \
|
||||
intsafe<t> cs2 = as op bs; \
|
||||
if (cs1.val() != cs2.val()) \
|
||||
{ \
|
||||
assert_msg(false, tostring(au)+#op+tostring(bu)+": expected "+tostring(cs1.val())+", got "+tostring(cs2.val())); \
|
||||
} \
|
||||
} \
|
||||
}
|
||||
|
||||
test()
|
||||
{
|
||||
TEST(uint8_t, +)
|
||||
TEST(uint8_t, -)
|
||||
TEST(uint8_t, *)
|
||||
TEST(uint8_t, <<)
|
||||
TEST( int8_t, +)
|
||||
TEST( int8_t, -)
|
||||
TEST( int8_t, *)
|
||||
TEST( int8_t, <<)
|
||||
}
|
||||
#endif
|
||||
239
arlib/intsafe.h
Normal file
239
arlib/intsafe.h
Normal file
@@ -0,0 +1,239 @@
|
||||
#pragma once
|
||||
#include "global.h"
|
||||
|
||||
#define ALLOPER(x) \
|
||||
x(+, +=) x(-, -=) x(*, *=) x(/, /=) x(%, %=) \
|
||||
x(|, |=) x(^, ^=) x(<<, <<=) x(>>, >>=)
|
||||
|
||||
//Overflow-safe integer class.
|
||||
//If an operation would overflow, it gets a special sentinel value instead, and all further operations return that.
|
||||
template<typename T> class intsafe {
|
||||
T data;
|
||||
|
||||
#define HANDLE_BASE(stype, utype) \
|
||||
static inline bool addov(utype a, utype b, utype* c) \
|
||||
{ \
|
||||
*c = a+b; /* rely on unsigned overflow wrapping */ \
|
||||
return *c < a; \
|
||||
} \
|
||||
static inline bool subov(utype a, utype b, utype* c) \
|
||||
{ \
|
||||
*c = a-b; \
|
||||
return (b > a); \
|
||||
} \
|
||||
static inline bool mulov(utype a, utype b, utype* c) \
|
||||
{ \
|
||||
*c = a*b; \
|
||||
return a!=0 && *c/a!=b; \
|
||||
} \
|
||||
static inline bool lslov(utype a, utype b, utype* c) \
|
||||
{ \
|
||||
if (b >= sizeof(utype)*8) return true; \
|
||||
*c = a<<b; \
|
||||
return (*c>>b != a); \
|
||||
} \
|
||||
static inline bool addov(stype a, stype b, stype* c) \
|
||||
{ \
|
||||
*c = (utype)a+(utype)b; \
|
||||
return (a>0 && b>0 && *c<0) || (a<0 && b<0 && *c>0); \
|
||||
} \
|
||||
static inline bool subov(stype a, stype b, stype* c) \
|
||||
{ \
|
||||
*c = (utype)a-(utype)b; \
|
||||
return (a>0 && b<0 && *c<0) || (a<0 && b>0 && *c>0); \
|
||||
} \
|
||||
static inline bool mulov(stype a, stype b, stype* c) \
|
||||
{ \
|
||||
stype min = ((stype)-1)<<(sizeof(stype)*8-1); \
|
||||
stype max = -(min+1); \
|
||||
/* not sure if this can be simplified */ \
|
||||
if (a<0 && b<0 && max/a > b) return true; \
|
||||
if (a<0 && b>0 && min/a < b) return true; \
|
||||
if (a>0 && b<0 && min/a > b) return true; \
|
||||
if (a>0 && b>0 && max/a < b) return true; \
|
||||
*c = a*b; \
|
||||
return false; \
|
||||
} \
|
||||
static inline bool lslov(stype a, stype b, stype* c) \
|
||||
{ \
|
||||
if (b<0 || b >= sizeof(stype)*8) return true; \
|
||||
*c = (a << b); \
|
||||
return (*c>>b != a); \
|
||||
}
|
||||
HANDLE_BASE(signed int, unsigned int)
|
||||
HANDLE_BASE(signed long, unsigned long)
|
||||
HANDLE_BASE(signed long long, unsigned long long)
|
||||
|
||||
#ifndef INTSAFE_SELFTEST
|
||||
#define HANDLE_EXT(name, op, type, ext) \
|
||||
static inline bool name(type a, type b, type* c) \
|
||||
{ \
|
||||
if (sizeof(type) == sizeof(ext)) return name((ext)a, (ext)b, (ext*)c); \
|
||||
if ((ext)a op (ext)b != (type)(a op b)) return true; \
|
||||
*c = (ext)a op (ext)b; \
|
||||
return false; \
|
||||
}
|
||||
HANDLE_EXT(addov, +, signed short, signed int)
|
||||
HANDLE_EXT(addov, +, signed char, signed int)
|
||||
HANDLE_EXT(addov, +, unsigned short, unsigned int)
|
||||
HANDLE_EXT(addov, +, unsigned char, unsigned int)
|
||||
HANDLE_EXT(subov, -, signed short, signed int)
|
||||
HANDLE_EXT(subov, -, signed char, signed int)
|
||||
HANDLE_EXT(subov, -, unsigned short, unsigned int)
|
||||
HANDLE_EXT(subov, -, unsigned char, unsigned int)
|
||||
HANDLE_EXT(mulov, *, signed short, signed int)
|
||||
HANDLE_EXT(mulov, *, signed char, signed int)
|
||||
HANDLE_EXT(mulov, *, unsigned short, unsigned int)
|
||||
HANDLE_EXT(mulov, *, unsigned char, unsigned int)
|
||||
HANDLE_EXT(lslov,<<, signed short, signed int)
|
||||
HANDLE_EXT(lslov,<<, signed char, signed int)
|
||||
HANDLE_EXT(lslov,<<, unsigned short, unsigned int)
|
||||
HANDLE_EXT(lslov,<<, unsigned char, unsigned int)
|
||||
#undef HANDLE_EXT
|
||||
#else
|
||||
//allow forcing the non-casting algorithm, so an exhaustive search can be done over the full range of some types
|
||||
HANDLE_BASE(signed short, unsigned short)
|
||||
HANDLE_BASE(signed char, unsigned char)
|
||||
#endif
|
||||
|
||||
#undef HANDLE_BASE
|
||||
|
||||
#if GCC_VERSION>=50000 && !defined(INTSAFE_SELFTEST)
|
||||
#define addov __builtin_add_overflow
|
||||
#define subov __builtin_sub_overflow
|
||||
#define mulov __builtin_mul_overflow
|
||||
#endif
|
||||
|
||||
public:
|
||||
static const T invalid = T(-1)<0 ? T(-1)<<(sizeof(T)*8-1) : T(-1);
|
||||
//static const T min = T(-1)<0 ? invalid+1 : 0;
|
||||
//static const T max = T(-1)<0 ? -min : T(-2);
|
||||
|
||||
intsafe() : data(0) {}
|
||||
template<typename U> intsafe(U val) { if (T(val)==val) data=val; else data=invalid; }
|
||||
bool valid() { return data!=invalid; }
|
||||
T val() { return data; }
|
||||
|
||||
intsafe<T>& operator=(intsafe<T> i) { data=i.val(); return *this; }
|
||||
|
||||
intsafe<T> operator++(int) { intsafe<T> r = *this; *this+=1; return r; }
|
||||
intsafe<T> operator--(int) { intsafe<T> r = *this; *this-=1; return r; }
|
||||
intsafe<T>& operator++() { *this+=1; return *this; }
|
||||
intsafe<T>& operator--() { *this+=1; return *this; }
|
||||
|
||||
#define OP(op, ope) \
|
||||
intsafe<T>& operator ope(intsafe<T> i) { *this = *this op i; return *this; }
|
||||
ALLOPER(OP)
|
||||
#undef OP
|
||||
|
||||
|
||||
intsafe<T> operator+(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
T ret;
|
||||
if (addov(val(), b.val(), &ret)) return invalid;
|
||||
else return ret;
|
||||
}
|
||||
intsafe<T> operator-(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
T ret;
|
||||
if (subov(val(), b.val(), &ret)) return invalid;
|
||||
else return ret;
|
||||
}
|
||||
intsafe<T> operator*(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
T ret;
|
||||
if (mulov(val(), b.val(), &ret)) return invalid;
|
||||
else return ret;
|
||||
}
|
||||
intsafe<T> operator/(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//overflows in division throw SIGFPE rather than truncating
|
||||
return val()/b.val();
|
||||
}
|
||||
intsafe<T> operator%(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//like division, overflow doesn't truncate
|
||||
return val()%b.val();
|
||||
}
|
||||
intsafe<T> operator&(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//can't overflow
|
||||
return val()&b.val();
|
||||
}
|
||||
intsafe<T> operator|(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//can't overflow (okay, it can become ::invalid, but that's fine)
|
||||
return val()|b.val();
|
||||
}
|
||||
intsafe<T> operator^(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//can't overflow
|
||||
return val()^b.val();
|
||||
}
|
||||
intsafe<T> operator<<(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
T ret;
|
||||
if (lslov(val(), b.val(), &ret)) return invalid;
|
||||
else return ret;
|
||||
}
|
||||
intsafe<T> operator>>(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return invalid;
|
||||
//can't overflow
|
||||
return val()>>b.val();
|
||||
}
|
||||
|
||||
bool operator==(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return false;
|
||||
return val()==b.val();
|
||||
}
|
||||
bool operator!=(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return true; // match NaN
|
||||
return val()!=b.val();
|
||||
}
|
||||
bool operator<(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return false;
|
||||
return val()<b.val();
|
||||
}
|
||||
bool operator<=(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return false;
|
||||
return val()<=b.val();
|
||||
}
|
||||
bool operator>(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return false;
|
||||
return val()>b.val();
|
||||
}
|
||||
bool operator>=(intsafe<T> b)
|
||||
{
|
||||
if (!valid() || !b.valid()) return false;
|
||||
return val()>=b.val();
|
||||
}
|
||||
};
|
||||
|
||||
#define OP(op, ope) \
|
||||
template<typename T> intsafe<T> operator op(T a, intsafe<T> b) { return intsafe<T>(a) op b; } \
|
||||
template<typename T> intsafe<T> operator op(intsafe<T> a, T b) { return b op intsafe<T>(a); }
|
||||
ALLOPER(OP)
|
||||
OP(==, _)
|
||||
OP(!=, _)
|
||||
OP(<, _)
|
||||
OP(<=, _)
|
||||
OP(>, _)
|
||||
OP(>=, _)
|
||||
#undef OP
|
||||
|
||||
#undef ALLOPER
|
||||
@@ -4,7 +4,7 @@
|
||||
//TODO:
|
||||
//- fetch howsmyssl, ensure the only failure is the session cache
|
||||
|
||||
#ifdef ARLIB_TEST
|
||||
#ifdef ARLIB_TESTggg // disable these because they take way too long
|
||||
//not in socket.h because this shouldn't really be used for anything, blocking is evil
|
||||
static array<byte> recvall(socket* sock, unsigned int len)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
#ifdef ARLIB_TEST
|
||||
#ifdef ARLIB_TESTRUNNER
|
||||
#ifndef ARLIB_TEST
|
||||
#define ARLIB_TEST
|
||||
#endif
|
||||
#include "test.h"
|
||||
#include "array.h"
|
||||
#include "gui/window.h"
|
||||
@@ -104,6 +107,8 @@ int main(int argc, char* argv[])
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ARLIB_TEST_ARLIB
|
||||
test() {}
|
||||
test() {}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -19,8 +19,8 @@ public:
|
||||
_testdecl(void(*func)(), const char * loc, const char * name);
|
||||
};
|
||||
|
||||
void _testfail(cstring name, int line);
|
||||
void _testeqfail(cstring name, int line, cstring expected, cstring actual);
|
||||
void _testfail(cstring why, int line);
|
||||
void _testeqfail(cstring why, int line, cstring expected, cstring actual);
|
||||
|
||||
void _teststack_push(int line);
|
||||
void _teststack_pop();
|
||||
@@ -32,6 +32,8 @@ void _teststack_pop();
|
||||
static void TESTFUNCNAME()
|
||||
#define assert_ret(x, ret) do { if (!(x)) { _testfail("\nFailed assertion " #x, __LINE__); return ret; } } while(0)
|
||||
#define assert(x) assert_ret(x,)
|
||||
#define assert_msg_ret(x, msg, ret) do { if (!(x)) { _testfail((string)"\nFailed assertion " #x ": "+msg, __LINE__); return ret; } } while(0)
|
||||
#define assert_msg(x, msg) assert_msg_ret(x,msg,)
|
||||
#define assert_eq(actual,expected) do { \
|
||||
if ((actual) != (expected)) \
|
||||
{ \
|
||||
|
||||
Reference in New Issue
Block a user