| [190a833] | 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 |  | 
|---|
| [5a894e12] | 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 |  | 
|---|
| [190a833] | 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) { | 
|---|
| [5a894e12] | 71 | throw (BadIndexException){ arrayIndex, index, size }; | 
|---|
| [190a833] | 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 | } | 
|---|