| 1 | // Use of the exception system where we provide our own functions.
 | 
|---|
| 2 | 
 | 
|---|
| 3 | #include <stdio.h>
 | 
|---|
| 4 | #include <string.h>
 | 
|---|
| 5 | // Using collections/string.hfa leads to a resolution error on snprintf.
 | 
|---|
| 6 | 
 | 
|---|
| 7 | exception BadIndexException {
 | 
|---|
| 8 |         int value;
 | 
|---|
| 9 |         int size;
 | 
|---|
| 10 |         char * message;
 | 
|---|
| 11 | };
 | 
|---|
| 12 | 
 | 
|---|
| 13 | const char * virtual_msg(BadIndexException * this) {
 | 
|---|
| 14 |         return this->virtual_table->msg(this);
 | 
|---|
| 15 | }
 | 
|---|
| 16 | 
 | 
|---|
| 17 | // Array length calculated to ususually be big enough.
 | 
|---|
| 18 | const size_t msg_size = 52;
 | 
|---|
| 19 | 
 | 
|---|
| 20 | char * format_bad_index(int value, int size) {
 | 
|---|
| 21 |         char * out = (char *)(void *)malloc(msg_size + 1);
 | 
|---|
| 22 |         snprintf(out, msg_size,
 | 
|---|
| 23 |                 "Out of Range Index %d (expected less than %d)", value, size);
 | 
|---|
| 24 |         return out;
 | 
|---|
| 25 | }
 | 
|---|
| 26 | 
 | 
|---|
| 27 | const char * msg(BadIndexException * this) {
 | 
|---|
| 28 |         if (this->message) {
 | 
|---|
| 29 |                 free(this->message);
 | 
|---|
| 30 |         }
 | 
|---|
| 31 |         this->message = format_bad_index(this->value, this->size);
 | 
|---|
| 32 |         return this->message;
 | 
|---|
| 33 | }
 | 
|---|
| 34 | 
 | 
|---|
| 35 | void copy(BadIndexException * dst, BadIndexException * src) {
 | 
|---|
| 36 |         // This is an easy detail to miss, you have to copy the table over.
 | 
|---|
| 37 |         dst->virtual_table = src->virtual_table;
 | 
|---|
| 38 | 
 | 
|---|
| 39 |         dst->value = src->value;
 | 
|---|
| 40 |         dst->size = src->size;
 | 
|---|
| 41 |         dst->message = (src->message) ? strndup(src->message, msg_size) : 0p;
 | 
|---|
| 42 | }
 | 
|---|
| 43 | 
 | 
|---|
| 44 | // Do not construct an exception without a vtable!
 | 
|---|
| 45 | void ?{}(BadIndexException&) = void;
 | 
|---|
| 46 | 
 | 
|---|
| 47 | void ?{}(BadIndexException & this,
 | 
|---|
| 48 |                 vtable(BadIndexException) & vt, int value, int size) {
 | 
|---|
| 49 |         this.virtual_table = &vt;
 | 
|---|
| 50 |         this.value = value;
 | 
|---|
| 51 |         this.size = size;
 | 
|---|
| 52 |         this.message = 0p;
 | 
|---|
| 53 | }
 | 
|---|
| 54 | 
 | 
|---|
| 55 | void ?{}(BadIndexException & this, BadIndexException that) {
 | 
|---|
| 56 |         copy(&this, &that);
 | 
|---|
| 57 | }
 | 
|---|
| 58 | 
 | 
|---|
| 59 | void ^?{}(BadIndexException & this) {
 | 
|---|
| 60 |         free(this.message);
 | 
|---|
| 61 | }
 | 
|---|
| 62 | 
 | 
|---|
| 63 | vtable(BadIndexException) arrayIndex = {
 | 
|---|
| 64 |         .msg = msg,
 | 
|---|
| 65 |         .copy = copy,
 | 
|---|
| 66 |         .^?{} = ^?{},
 | 
|---|
| 67 | };
 | 
|---|
| 68 | 
 | 
|---|
| 69 | // This is not supposed to be a real range check, but that's the idea:
 | 
|---|
| 70 | void failRangeCheck(int index, int size) {
 | 
|---|
| 71 |         throw (BadIndexException){ arrayIndex, index, size };
 | 
|---|
| 72 | }
 | 
|---|
| 73 | 
 | 
|---|
| 74 | int atDefault(int fallback) {
 | 
|---|
| 75 |         try {
 | 
|---|
| 76 |                 failRangeCheck(10, 8);
 | 
|---|
| 77 |         } catch (BadIndexException * error) {
 | 
|---|
| 78 |                 printf("%s\n", virtual_msg(error));
 | 
|---|
| 79 |         }
 | 
|---|
| 80 |         return fallback;
 | 
|---|
| 81 | }
 | 
|---|
| 82 | 
 | 
|---|
| 83 | int main() {
 | 
|---|
| 84 |         int value = atDefault(5);
 | 
|---|
| 85 |         printf("%d\n", value);
 | 
|---|
| 86 | }
 | 
|---|