218 lines
13 KiB
HTML
218 lines
13 KiB
HTML
<html>
|
|
<title>EA Assert</title>
|
|
<body>
|
|
<font face="tahoma">
|
|
<h1>EA Assert</h1>
|
|
<hr>
|
|
A simple lightweight package. Use...
|
|
<font color="#0000FF"><pre>
|
|
#include "EAAssert/eaassert.h"
|
|
</pre></font>
|
|
And get the following macros...
|
|
<ul>
|
|
<li>
|
|
<code><font color="#FF00EE">EA_ASSERT(expr)</font></code> where <code><font color="#000099">
|
|
expr</font></code> is an expression that evaluates to a boolean. For
|
|
example... <font color="#000099">
|
|
<pre> EA_ASSERT(3 != 5);</pre>
|
|
</font>
|
|
<li>
|
|
<code><font color="#FF00EE">EA_ASSERT_MSG(expr, msg)</font></code> where <code><font color="#000099">
|
|
msg</font></code> is an string (i.e., a <code><font color="#000099">char*</font></code>).
|
|
For example... <font color="#000099">
|
|
<pre> EA_ASSERT_MSG(3 != 5, "mathematics is flawed");</pre>
|
|
</font>
|
|
<li>
|
|
<code><font color="#FF00EE">EA_ASSERT_FORMATTED(expr, fmt)</font></code> where <code>
|
|
<font color="#000099">fmt</font></code> is a parentheses wrapped tuple of
|
|
which the first parameter is a string (i.e., a <code><font color="#000099">char*</font></code>)
|
|
and the rest are <code><font color="#000099">printf</font></code> style
|
|
parameters. For example... <font color="#000099">
|
|
<pre> EA_ASSERT_FORMATTED(3 != 5, ("The answer is: %d", 42));</pre>
|
|
</font>
|
|
<li>
|
|
<code><font color="#FF00EE">EA_FAIL()</font></code> similar to <code><font color="#000099">
|
|
EA_ASSERT(false)</font></code>
|
|
but avoids warning of constant conditional expression.
|
|
<li>
|
|
<code><font color="#FF00EE">EA_FAIL_MSG(msg)</font></code> similar to <code><font color="#000099">
|
|
EA_ASSERT_MSG(false, msg);</font></code>
|
|
<li>
|
|
<code><font color="#FF00EE">EA_FAIL_FORMATTED(fmt)</font></code> similar to <code><font color="#000099">
|
|
EA_ASSERT_FORMATTED(false, fmt);</font></code></li>
|
|
</ul>
|
|
For compatibility reasons (with existing EATrace practice), there are synonyms for <font color="#FF00EE">EA_ASSERT_MSG</font>, defined as <font color="#FF00EE">EA_ASSERT_MESSAGE</font> and <font color="#FF00EE">EA_ASSERT_M</font>.
|
|
<hr>
|
|
<h2>Enabling and Disabling</h2>
|
|
Whether or not <code><font color="#000099">EA_ASSERT</font></code> is enabled hinges on the following logic...
|
|
<font color="#000099">
|
|
<pre>
|
|
#ifdef EA_DEBUG
|
|
#define EA_ASSERT_ENABLED
|
|
#endif
|
|
|
|
#ifndef EA_ASSERT
|
|
#if EA_ASSERT_ENABLED
|
|
#define EA_ASSERT(expr) ...definition of EA_ASSERT...
|
|
#else
|
|
#define EA_ASSERT(expr) ((void)0)
|
|
#endif
|
|
#endif
|
|
</pre>
|
|
</font>
|
|
<hr />
|
|
<h2>Design Considerations</h2>
|
|
Below are some thoughts that went into the creation of this package...
|
|
<ul>
|
|
<li>Aim to be lightweight and simple.</li>
|
|
<li>Become the single most used ubiquitous assert technology, along EA Base lines.</li>
|
|
<li>Have minimal dependencies; e.g. EA Base only.</li>
|
|
<li>Ability for users to override functionality.</li>
|
|
<li>Ability for users to redirect assertions to their application's given system.</li>
|
|
<li>Ability for users to extend the system.</li>
|
|
<li>Enable users to rebuild other technology but have it use their assert system.</li>
|
|
<li>Make it easy to supply your own assert-failure callback function, but...
|
|
<ul>
|
|
<li>...don't enforce a link-time definition (i.e., provide a default)</li>
|
|
<li>...don't require a global #define.</li>
|
|
</ul>
|
|
The result is that we require a CPP file (and resulting library) where we can declare and store a function pointer that points to the current assert handler.</li>
|
|
</ul>
|
|
<hr />
|
|
<h2>Integration</h2>
|
|
<p>To use <code><font color="#000099">EA_ASSERT</font></code> in your own code you just include the header and use it.</p>
|
|
<p>To overwrite the default handler for assert failure, you need to implement the following function <font color="#000099">
|
|
<pre>
|
|
bool EAAssertFailure(
|
|
|
|
const char* expr, <font color=#009900>// Stringized version of the assert expression.</font>
|
|
const char* filename, <font color=#009900>// Name of the file in which the assert occured.</font>
|
|
int line, <font color=#009900>// Line number on which the assert occured.</font>
|
|
const char* function, <font color=#009900>// Name of the function the assert occured in.</font>
|
|
const char* msg, <font color=#009900>// Optional descriptive message.</font>
|
|
va_list args <font color=#009900>// Variable argument list (printf style) in case msg contains formatters.</font>
|
|
|
|
);
|
|
</pre>
|
|
</font>The return value of this function should be <code><font color="#000099">true</font></code>
|
|
if you want the failed assert to break into the debugger and <code><font color="#000099">
|
|
false</font></code>
|
|
if you want to continue running past the assert.
|
|
<p>To enable the use of this function, use:<font color="#000099">
|
|
<pre>
|
|
EA::Assert::SetFailureCallback(&yourCallback);
|
|
</pre>
|
|
</font>
|
|
</p>
|
|
<P>The simplest possible implementation of this function (which happens to be the default) just returns <code><font color="#000099">true</font></code> immediately, always triggering a debug break.</P>
|
|
<p>
|
|
For reference, here's an example implementation of <code><font color="#000099">EAAssertFailure</font></code>
|
|
that you can copy paste into your own code. <font color="#000099">
|
|
<pre>
|
|
bool EAAssertFailure(const char* expr, const char* filename, int line, const char* function, const char* msg, va_list args)
|
|
{
|
|
const int size = 1024;
|
|
char output[size + 1] = {};
|
|
char fmtMsg[size + 1] = {};
|
|
|
|
_vsnprintf(fmtMsg, size, msg, args);
|
|
_snprintf(output, size, "%s(%d) : assert failed: '%s' in function: %s\n, message: %s", filename, line, expr, function, fmtMsg);
|
|
|
|
printf(output);
|
|
|
|
return true;
|
|
}
|
|
</pre>
|
|
</font>
|
|
<P></P>
|
|
<h3>If You already Have Your Own Asserts</h3>
|
|
If you already have your own asserts and would like other technology to use
|
|
yours, you can easily forward <code><font color="#000099">EA_ASSERT</font></code>
|
|
to your own implementation. The trick is in the <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
|
macro. Define this to the name of your own header file that has equivalents of
|
|
the macros defined above (make sure you provide all of them). For example, you
|
|
could put the following in a file called "game/my_own_awesome_assert.h"... <font color="#000099">
|
|
<pre>
|
|
#define EA_ASSERT(expr) MY_OWN_AWESOME_ASSERT(expr)
|
|
#define EA_ASSERT_MSG(expr, msg) MY_OWN_AWESOME_ASSERT(expr)
|
|
#define EA_ASSERT_FORMATTED(expr, fmt) MY_OWN_AWESOME_ASSERT(expr)
|
|
#define EA_FAIL() MY_OWN_AWESOME_ASSERT(false)
|
|
#define EA_FAIL_MSG(msg) MY_OWN_AWESOME_ASSERT(false)
|
|
#define EA_FAIL_FORMATTED(fmt) MY_OWN_AWESOME_ASSERT(false)
|
|
</pre>
|
|
</font>Next, define <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
|
to <code><font color="#000099">"game/my_own_awesome_assert.h"</font></code> (including
|
|
the quotes) when you build <code><font color="#000099">EA_ASSERT</font></code> using
|
|
technology and it will automatically use your assert instead.
|
|
<hr>
|
|
<h2>Frequently Asked Questions</h2>
|
|
<ul>
|
|
<li>
|
|
<b>Why don't you supply <code><font color="#000099">EA_WARNING</font></code> macros?</b><p>Because
|
|
few people can use warnings properly. This often results in games spewing so
|
|
much output to the console that nobody cares anymore. If the problem is serious
|
|
enough, just assert. If it's not serious enough, put a bright pink texture on
|
|
it in the game.</p>
|
|
<li>
|
|
<b>But I really need <code><font color="#000099">EA_WARNING</font></code>, can't
|
|
you add it?</b><p>The truth is, the original author of this package didn't need
|
|
them. Warning support would increase the complexity of this package of
|
|
proportion (now you need warning levels, etc.) If you need warnings, write your
|
|
own.</p>
|
|
<li>
|
|
<b>I already have my own definitions of the <code><font color="#000099">EA_ASSERT</font></code>
|
|
macro and others, now what?</b><p>Use the <code><font color="#000099">EA_ASSERT_HAVE_OWN_HEADER</font></code>
|
|
feature described above. Now any library that uses <code><font color="#000099">EA_ASSERT</font></code>
|
|
automatically leverages your assert.</p>
|
|
<li>
|
|
<b>I need multilevel asserts, only enabling some when I really need to. Can you add
|
|
it?</b><p>This often occurs when you have asserts in a tight inner loop that
|
|
you only want enabled every now and then when you do very strict integrity
|
|
checking. Unfortunately it would complicate this library too much. We don't
|
|
feel enough technologies have a need for this. Fortunately you can implement
|
|
this yourself fairly easily by doing... <font color="#000099">
|
|
<pre>
|
|
#if MY_TECH_DEBUG_LEVEL == 1
|
|
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
|
|
#define MY_TECH_HARDCORE_ASSERT(expr) ((void)0)
|
|
#else if MY_TECH_DEBUG_LEVEL == 1
|
|
#define MY_TECH_ASSERT(expr) EA_ASSERT(expr)
|
|
#define MY_TECH_HARDCORE_ASSERT(expr) EA_ASSERT(expr)
|
|
#endif
|
|
</pre>
|
|
</font>That way you can still leverage <code><font color="#000099">EA_ASSERT</font></code>
|
|
but have more fine grained control over assert subsets in your technology.
|
|
<P></P>
|
|
<li>
|
|
<b>Why aren't your asserts ignorable?</b><p>Because it would make things more
|
|
complicated than I'd like. Furthermore, ignorable asserts often flawed. People
|
|
end up using them to signal user errors that should be handled differently
|
|
(proper fallback mechanisms, bright pink textures, etc.). What happens is that
|
|
everybody starts ignoring asserts when they happen rather than fixing them or
|
|
reporting them. You get away with this for a while, until one day shit hits the
|
|
fan. Asserts are for programmer error, exceptions and other mechanisms are for
|
|
user error.</p>
|
|
<p>That said if you desperately need ignorable asserts, all is not lost. Either use
|
|
the <code><font color="#000099">#EA_ASSERT_HAVE_OWN_HEADER</font></code> feature,
|
|
or simply catch the filename and line-number in the handler function. Stick
|
|
them as a pair into a set. Whenever you find them in the set, return false from
|
|
the assert handler to ignore the assert.</p>
|
|
<li>
|
|
<b>Why isn't platform X supported?</b><p>I don't know. Let me know what its
|
|
break-into-debugger statement is and I'll gladly add it.</p>
|
|
<li>
|
|
<b>Why don't you have feature X?</b><p>Probably because I didn't need it.
|
|
Alternatively, because it would make this package more complicated than I'd
|
|
like. Perhaps feature X is best implemented in your own technology? Of course,
|
|
you can always try sending us an email. Maybe we'll add feature X.</p>
|
|
</li>
|
|
</ul>
|
|
<hr />
|
|
<h2>Acknowledgements</h2>
|
|
|
|
Input for this package came from Paul Pedriana, Ian Davids, James Fairweather, Max Burke, Bob Summerwill and others.
|
|
</font>
|
|
|
|
</body>
|
|
</html>
|