From d4c7e7875392b4fe87c23f4208179d83a0686f4e Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 7 Oct 2014 20:01:02 -0400 Subject: [PATCH] Alloc/Dealloc works. Continuing testing. Todo: test linked-list interface methods Signed-off-by: unknown --- dynarrc/AllTests.c | 25 + dynarrc/CuTest.c | 342 +++++++++++++ dynarrc/CuTest.h | 116 +++++ dynarrc/CuTestTest.c | 711 +++++++++++++++++++++++++++ dynarrc/common.h | 18 + dynarrc/dynarr.h | 552 ++------------------- dynarrc/dynarrc.coremethods.h | 61 +++ dynarrc/dynarrc.freeseglistmethods.h | 71 +++ dynarrc/dynarrc.freeseglistonce.h | 38 ++ dynarrc/dynarrc.interface.h | 21 + dynarrc/dynarrc.segbankmethods.h | 135 +++++ dynarrc/dynarrc.segmentmethods.h | 96 ++++ dynarrc/dynarrc.vars.h | 103 ++++ dynarrc/dynarrc.vcxproj | 16 +- dynarrc/dynarrc.vcxproj.filters | 32 +- dynarrc/main.c | 42 -- dynarrc/test.c | 196 ++++++++ 17 files changed, 2017 insertions(+), 558 deletions(-) create mode 100644 dynarrc/AllTests.c create mode 100644 dynarrc/CuTest.c create mode 100644 dynarrc/CuTest.h create mode 100644 dynarrc/CuTestTest.c create mode 100644 dynarrc/dynarrc.coremethods.h create mode 100644 dynarrc/dynarrc.freeseglistmethods.h create mode 100644 dynarrc/dynarrc.freeseglistonce.h create mode 100644 dynarrc/dynarrc.interface.h create mode 100644 dynarrc/dynarrc.segbankmethods.h create mode 100644 dynarrc/dynarrc.segmentmethods.h create mode 100644 dynarrc/dynarrc.vars.h delete mode 100644 dynarrc/main.c create mode 100644 dynarrc/test.c diff --git a/dynarrc/AllTests.c b/dynarrc/AllTests.c new file mode 100644 index 0000000..42beda6 --- /dev/null +++ b/dynarrc/AllTests.c @@ -0,0 +1,25 @@ +#include + +#include "CuTest.h" + +CuSuite* CuGetSuite(); +// CuSuite* CuStringGetSuite(); + +void RunAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = CuSuiteNew(); + + CuSuiteAddSuite(suite, CuGetSuite()); + CuSuiteAddSuite(suite, CuStringGetSuite()); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); +} + +int main(void) +{ + RunAllTests(); +} diff --git a/dynarrc/CuTest.c b/dynarrc/CuTest.c new file mode 100644 index 0000000..257c1d2 --- /dev/null +++ b/dynarrc/CuTest.c @@ -0,0 +1,342 @@ +#include "common.h" + + +#include +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * CuStr + *-------------------------------------------------------------------------*/ + +char* CuStrAlloc(int size) +{ + char* newStr = (char*) malloc( sizeof(char) * (size) ); + return newStr; +} + +char* CuStrCopy(const char* old) +{ + int len = strlen(old); + char* newStr = CuStrAlloc(len + 1); + strcpy(newStr, old); + return newStr; +} + +/*-------------------------------------------------------------------------* + * CuString + *-------------------------------------------------------------------------*/ + +void CuStringInit(CuString* str) +{ + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; +} + +CuString* CuStringNew(void) +{ + CuString* str = (CuString*) malloc(sizeof(CuString)); + str->length = 0; + str->size = STRING_MAX; + str->buffer = (char*) malloc(sizeof(char) * str->size); + str->buffer[0] = '\0'; + return str; +} + +void CuStringDelete(CuString *str) +{ + if (!str) return; + FREE_SAFE(str->buffer); + FREE_SAFE(str); +} + +void CuStringResize(CuString* str, int newSize) +{ + str->buffer = (char*) realloc(str->buffer, sizeof(char) * newSize); + str->size = newSize; +} + +void CuStringAppend(CuString* str, const char* text) +{ + int length; + + if (text == NULL) { + text = "NULL"; + } + + length = strlen(text); + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + str->length += length; + strcat(str->buffer, text); +} + +void CuStringAppendChar(CuString* str, char ch) +{ + char text[2]; + text[0] = ch; + text[1] = '\0'; + CuStringAppend(str, text); +} + +void CuStringAppendFormat(CuString* str, const char* format, ...) +{ + va_list argp; + char buf[HUGE_STRING_LEN]; + va_start(argp, format); + vsprintf(buf, format, argp); + va_end(argp); + CuStringAppend(str, buf); +} + +void CuStringInsert(CuString* str, const char* text, int pos) +{ + int length = strlen(text); + if (pos > str->length) + pos = str->length; + if (str->length + length + 1 >= str->size) + CuStringResize(str, str->length + length + 1 + STRING_INC); + memmove(str->buffer + pos + length, str->buffer + pos, (str->length - pos) + 1); + str->length += length; + memcpy(str->buffer + pos, text, length); +} + +/*-------------------------------------------------------------------------* + * CuTest + *-------------------------------------------------------------------------*/ + +void CuTestInit(CuTest* t, const char* name, TestFunction function) +{ + t->name = CuStrCopy(name); + t->failed = 0; + t->ran = 0; + t->message = NULL; + t->function = function; + t->jumpBuf = NULL; +} + +CuTest* CuTestNew(const char* name, TestFunction function) +{ + CuTest* tc = CU_ALLOC(CuTest); + CuTestInit(tc, name, function); + return tc; +} + +void CuTestDelete(CuTest *t) +{ + if (!t) return; + FREE_SAFE(t->name); + FREE_SAFE(t); +} + +void CuTestRun(CuTest* tc) +{ + jmp_buf buf; + tc->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + tc->ran = 1; + (tc->function)(tc); + } + tc->jumpBuf = 0; +} + +static void CuFailInternal(CuTest* tc, const char* file, int line, CuString* string) +{ + char buf[HUGE_STRING_LEN]; + + sprintf(buf, "%s:%d: ", file, line); + CuStringInsert(string, buf, 0); + + tc->failed = 1; + tc->message = string->buffer; + if (tc->jumpBuf != 0) longjmp(*(tc->jumpBuf), 0); +} + +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message) +{ + CuString string; + + CuStringInit(&string); + if (message2 != NULL) + { + CuStringAppend(&string, message2); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, message); + CuFailInternal(tc, file, line, &string); +} + +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition) +{ + if (condition) return; + CuFail_Line(tc, file, line, NULL, message); +} + +void CuAssertStrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + const char* expected, const char* actual) +{ + CuString string; + if ((expected == NULL && actual == NULL) || + (expected != NULL && actual != NULL && + strcmp(expected, actual) == 0)) + { + return; + } + + CuStringInit(&string); + if (message != NULL) + { + CuStringAppend(&string, message); + CuStringAppend(&string, ": "); + } + CuStringAppend(&string, "expected <"); + CuStringAppend(&string, expected); + CuStringAppend(&string, "> but was <"); + CuStringAppend(&string, actual); + CuStringAppend(&string, ">"); + CuFailInternal(tc, file, line, &string); +} + +void CuAssertIntEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + int expected, int actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected <%d> but was <%d>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertDblEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + double expected, double actual, double delta) +{ + char buf[STRING_MAX]; + if (fabs(expected - actual) <= delta) return; + sprintf(buf, "expected <%f> but was <%f>", expected, actual); + + CuFail_Line(tc, file, line, message, buf); +} + +void CuAssertPtrEquals_LineMsg(CuTest* tc, const char* file, int line, const char* message, + void* expected, void* actual) +{ + char buf[STRING_MAX]; + if (expected == actual) return; + sprintf(buf, "expected pointer <0x%p> but was <0x%p>", expected, actual); + CuFail_Line(tc, file, line, message, buf); +} + + +/*-------------------------------------------------------------------------* + * CuSuite + *-------------------------------------------------------------------------*/ + +void CuSuiteInit(CuSuite* testSuite) +{ + testSuite->count = 0; + testSuite->failCount = 0; + memset(testSuite->list, 0, sizeof(testSuite->list)); +} + +CuSuite* CuSuiteNew(void) +{ + CuSuite* testSuite = CU_ALLOC(CuSuite); + CuSuiteInit(testSuite); + return testSuite; +} + +void CuSuiteDelete(CuSuite *testSuite) +{ + unsigned int n; + for (n=0; n < MAX_TEST_CASES; n++) + { + if (testSuite->list[n]) + { + CuTestDelete(testSuite->list[n]); + } + } + FREE_SAFE(testSuite); + +} + +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase) +{ + assert(testSuite->count < MAX_TEST_CASES); + testSuite->list[testSuite->count] = testCase; + testSuite->count++; +} + +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2) +{ + int i; + for (i = 0 ; i < testSuite2->count ; ++i) + { + CuTest* testCase = testSuite2->list[i]; + CuSuiteAdd(testSuite, testCase); + } +} + +void CuSuiteRun(CuSuite* testSuite) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuTestRun(testCase); + if (testCase->failed) { testSuite->failCount += 1; } + } +} + +void CuSuiteSummary(CuSuite* testSuite, CuString* summary) +{ + int i; + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + CuStringAppend(summary, testCase->failed ? "F" : "."); + } + CuStringAppend(summary, "\n\n"); +} + +void CuSuiteDetails(CuSuite* testSuite, CuString* details) +{ + int i; + int failCount = 0; + + if (testSuite->failCount == 0) + { + int passCount = testSuite->count - testSuite->failCount; + const char* testWord = passCount == 1 ? "test" : "tests"; + CuStringAppendFormat(details, "OK (%d %s)\n", passCount, testWord); + } + else + { + if (testSuite->failCount == 1) + CuStringAppend(details, "There was 1 failure:\n"); + else + CuStringAppendFormat(details, "There were %d failures:\n", testSuite->failCount); + + for (i = 0 ; i < testSuite->count ; ++i) + { + CuTest* testCase = testSuite->list[i]; + if (testCase->failed) + { + failCount++; + CuStringAppendFormat(details, "%d) %s: %s\n", + failCount, testCase->name, testCase->message); + } + } + CuStringAppend(details, "\n!!!FAILURES!!!\n"); + + CuStringAppendFormat(details, "Runs: %d ", testSuite->count); + CuStringAppendFormat(details, "Passes: %d ", testSuite->count - testSuite->failCount); + CuStringAppendFormat(details, "Fails: %d\n", testSuite->failCount); + } +} diff --git a/dynarrc/CuTest.h b/dynarrc/CuTest.h new file mode 100644 index 0000000..8b32773 --- /dev/null +++ b/dynarrc/CuTest.h @@ -0,0 +1,116 @@ +#ifndef CU_TEST_H +#define CU_TEST_H + +#include +#include + +#define CUTEST_VERSION "CuTest 1.5" + +/* CuString */ + +char* CuStrAlloc(int size); +char* CuStrCopy(const char* old); + +#define CU_ALLOC(TYPE) ((TYPE*) malloc(sizeof(TYPE))) + +#define HUGE_STRING_LEN 8192 +#define STRING_MAX 256 +#define STRING_INC 256 + +typedef struct +{ + int length; + int size; + char* buffer; +} CuString; + +void CuStringInit(CuString* str); +CuString* CuStringNew(void); +void CuStringRead(CuString* str, const char* path); +void CuStringAppend(CuString* str, const char* text); +void CuStringAppendChar(CuString* str, char ch); +void CuStringAppendFormat(CuString* str, const char* format, ...); +void CuStringInsert(CuString* str, const char* text, int pos); +void CuStringResize(CuString* str, int newSize); +void CuStringDelete(CuString* str); + +/* CuTest */ + +typedef struct CuTest CuTest; + +typedef void (*TestFunction)(CuTest *); + +struct CuTest +{ + char* name; + TestFunction function; + int failed; + int ran; + const char* message; + jmp_buf *jumpBuf; +}; + +void CuTestInit(CuTest* t, const char* name, TestFunction function); +CuTest* CuTestNew(const char* name, TestFunction function); +void CuTestRun(CuTest* tc); +void CuTestDelete(CuTest *t); + +/* Internal versions of assert functions -- use the public versions */ +void CuFail_Line(CuTest* tc, const char* file, int line, const char* message2, const char* message); +void CuAssert_Line(CuTest* tc, const char* file, int line, const char* message, int condition); +void CuAssertStrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + const char* expected, const char* actual); +void CuAssertIntEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + int expected, int actual); +void CuAssertDblEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + double expected, double actual, double delta); +void CuAssertPtrEquals_LineMsg(CuTest* tc, + const char* file, int line, const char* message, + void* expected, void* actual); + +/* public assert functions */ + +#define CuFail(tc, ms) CuFail_Line( (tc), __FILE__, __LINE__, NULL, (ms)) +#define CuAssert(tc, ms, cond) CuAssert_Line((tc), __FILE__, __LINE__, (ms), (cond)) +#define CuAssertTrue(tc, cond) CuAssert_Line((tc), __FILE__, __LINE__, "assert failed", (cond)) + +#define CuAssertStrEquals(tc,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertStrEquals_Msg(tc,ms,ex,ac) CuAssertStrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertIntEquals(tc,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertIntEquals_Msg(tc,ms,ex,ac) CuAssertIntEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) +#define CuAssertDblEquals(tc,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac),(dl)) +#define CuAssertDblEquals_Msg(tc,ms,ex,ac,dl) CuAssertDblEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac),(dl)) +#define CuAssertPtrEquals(tc,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,NULL,(ex),(ac)) +#define CuAssertPtrEquals_Msg(tc,ms,ex,ac) CuAssertPtrEquals_LineMsg((tc),__FILE__,__LINE__,(ms),(ex),(ac)) + +#define CuAssertPtrNotNull(tc,p) CuAssert_Line((tc),__FILE__,__LINE__,"null pointer unexpected",(p != NULL)) +#define CuAssertPtrNotNullMsg(tc,msg,p) CuAssert_Line((tc),__FILE__,__LINE__,(msg),(p != NULL)) + +/* CuSuite */ + +#define MAX_TEST_CASES 1024 + +#define SUITE_ADD_TEST(SUITE,TEST) CuSuiteAdd(SUITE, CuTestNew(#TEST, TEST)) + +typedef struct +{ + int count; + CuTest* list[MAX_TEST_CASES]; + int failCount; + +} CuSuite; + + +void CuSuiteInit(CuSuite* testSuite); +CuSuite* CuSuiteNew(void); +void CuSuiteDelete(CuSuite *testSuite); +void CuSuiteAdd(CuSuite* testSuite, CuTest *testCase); +void CuSuiteAddSuite(CuSuite* testSuite, CuSuite* testSuite2); +void CuSuiteRun(CuSuite* testSuite); +void CuSuiteSummary(CuSuite* testSuite, CuString* summary); +void CuSuiteDetails(CuSuite* testSuite, CuString* details); + +#endif /* CU_TEST_H */ diff --git a/dynarrc/CuTestTest.c b/dynarrc/CuTestTest.c new file mode 100644 index 0000000..dd38bc5 --- /dev/null +++ b/dynarrc/CuTestTest.c @@ -0,0 +1,711 @@ +#include "common.h" + +#include +#include +#include +#include +#include + +#include "CuTest.h" + +/*-------------------------------------------------------------------------* + * Helper functions + *-------------------------------------------------------------------------*/ + +#define CompareAsserts(tc, message, expected, actual) X_CompareAsserts((tc), __FILE__, __LINE__, (message), (expected), (actual)) + +static void X_CompareAsserts(CuTest* tc, const char *file, int line, const char* message, const char* expected, const char* actual) +{ + int mismatch; + if (expected == NULL || actual == NULL) { + mismatch = (expected != NULL || actual != NULL); + } else { + const char *front = __FILE__ ":"; + const size_t frontLen = strlen(front); + const size_t expectedLen = strlen(expected); + + const char *matchStr = actual; + + mismatch = (strncmp(matchStr, front, frontLen) != 0); + if (!mismatch) { + matchStr = strchr(matchStr + frontLen, ':'); + mismatch |= (matchStr == NULL || strncmp(matchStr, ": ", 2)); + if (!mismatch) { + matchStr += 2; + mismatch |= (strncmp(matchStr, expected, expectedLen) != 0); + } + } + } + + CuAssert_Line(tc, file, line, message, !mismatch); +} + +/*-------------------------------------------------------------------------* + * CuString Test + *-------------------------------------------------------------------------*/ + +void TestCuStringNew(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuAssertTrue(tc, 0 == str->length); + CuAssertTrue(tc, 0 != str->size); + CuAssertStrEquals(tc, "", str->buffer); +} + + +void TestCuStringAppend(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, "hello"); + CuAssertIntEquals(tc, 5, str->length); + CuAssertStrEquals(tc, "hello", str->buffer); + CuStringAppend(str, " world"); + CuAssertIntEquals(tc, 11, str->length); + CuAssertStrEquals(tc, "hello world", str->buffer); +} + + +void TestCuStringAppendNULL(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, NULL); + CuAssertIntEquals(tc, 4, str->length); + CuAssertStrEquals(tc, "NULL", str->buffer); +} + + +void TestCuStringAppendChar(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppendChar(str, 'a'); + CuStringAppendChar(str, 'b'); + CuStringAppendChar(str, 'c'); + CuStringAppendChar(str, 'd'); + CuAssertIntEquals(tc, 4, str->length); + CuAssertStrEquals(tc, "abcd", str->buffer); +} + + +void TestCuStringInserts(CuTest* tc) +{ + CuString* str = CuStringNew(); + CuStringAppend(str, "world"); + CuAssertIntEquals(tc, 5, str->length); + CuAssertStrEquals(tc, "world", str->buffer); + CuStringInsert(str, "hell", 0); + CuAssertIntEquals(tc, 9, str->length); + CuAssertStrEquals(tc, "hellworld", str->buffer); + CuStringInsert(str, "o ", 4); + CuAssertIntEquals(tc, 11, str->length); + CuAssertStrEquals(tc, "hello world", str->buffer); + CuStringInsert(str, "!", 11); + CuAssertIntEquals(tc, 12, str->length); + CuAssertStrEquals(tc, "hello world!", str->buffer); +} + + +void TestCuStringResizes(CuTest* tc) +{ + CuString* str = CuStringNew(); + int i; + for(i = 0 ; i < STRING_MAX ; ++i) + { + CuStringAppend(str, "aa"); + } + CuAssertTrue(tc, STRING_MAX * 2 == str->length); + CuAssertTrue(tc, STRING_MAX * 2 <= str->size); +} + +CuSuite* CuStringGetSuite(void) +{ + CuSuite* suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, TestCuStringNew); + SUITE_ADD_TEST(suite, TestCuStringAppend); + SUITE_ADD_TEST(suite, TestCuStringAppendNULL); + SUITE_ADD_TEST(suite, TestCuStringAppendChar); + SUITE_ADD_TEST(suite, TestCuStringInserts); + SUITE_ADD_TEST(suite, TestCuStringResizes); + + return suite; +} + +/*-------------------------------------------------------------------------* + * CuTest Test + *-------------------------------------------------------------------------*/ + +void TestPasses(CuTest* tc) +{ + CuAssert(tc, "test should pass", 1 == 0 + 1); +} + +void zTestFails(CuTest* tc) +{ + CuAssert(tc, "test should fail", 1 == 1 + 1); +} + + +void TestCuTestNew(CuTest* tc) +{ + CuTest* tc2 = CuTestNew("MyTest", TestPasses); + CuAssertStrEquals(tc, "MyTest", tc2->name); + CuAssertTrue(tc, !tc2->failed); + CuAssertTrue(tc, tc2->message == NULL); + CuAssertTrue(tc, tc2->function == TestPasses); + CuAssertTrue(tc, tc2->ran == 0); + CuAssertTrue(tc, tc2->jumpBuf == NULL); +} + + +void TestCuTestInit(CuTest *tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", TestPasses); + CuAssertStrEquals(tc, "MyTest", tc2.name); + CuAssertTrue(tc, !tc2.failed); + CuAssertTrue(tc, tc2.message == NULL); + CuAssertTrue(tc, tc2.function == TestPasses); + CuAssertTrue(tc, tc2.ran == 0); + CuAssertTrue(tc, tc2.jumpBuf == NULL); +} + +void TestCuAssert(CuTest* tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", TestPasses); + + CuAssert(&tc2, "test 1", 5 == 4 + 1); + CuAssertTrue(tc, !tc2.failed); + CuAssertTrue(tc, tc2.message == NULL); + + CuAssert(&tc2, "test 2", 0); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 2", tc2.message); + + CuAssert(&tc2, "test 3", 1); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 2", tc2.message); + + CuAssert(&tc2, "test 4", 0); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssert didn't fail", "test 4", tc2.message); + +} + +void TestCuAssertPtrEquals_Success(CuTest* tc) +{ + CuTest tc2; + int x; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test success case */ + CuAssertPtrEquals(&tc2, &x, &x); + CuAssertTrue(tc, ! tc2.failed); + CuAssertTrue(tc, NULL == tc2.message); +} + +void TestCuAssertPtrEquals_Failure(CuTest* tc) +{ + CuTest tc2; + int x; + int* nullPtr = NULL; + char expected_message[STRING_MAX]; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test failing case */ + sprintf(expected_message, "expected pointer <0x%p> but was <0x%p>", nullPtr, &x); + CuAssertPtrEquals(&tc2, NULL, &x); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssertPtrEquals failed", expected_message, tc2.message); +} + +void TestCuAssertPtrNotNull_Success(CuTest* tc) +{ + CuTest tc2; + int x; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test success case */ + CuAssertPtrNotNull(&tc2, &x); + CuAssertTrue(tc, ! tc2.failed); + CuAssertTrue(tc, NULL == tc2.message); +} + +void TestCuAssertPtrNotNull_Failure(CuTest* tc) +{ + CuTest tc2; + + CuTestInit(&tc2, "MyTest", TestPasses); + + /* test failing case */ + CuAssertPtrNotNull(&tc2, NULL); + CuAssertTrue(tc, tc2.failed); + CompareAsserts(tc, "CuAssertPtrNotNull failed", "null pointer unexpected", tc2.message); +} + +void TestCuTestRun(CuTest* tc) +{ + CuTest tc2; + CuTestInit(&tc2, "MyTest", zTestFails); + CuTestRun(&tc2); + + CuAssertStrEquals(tc, "MyTest", tc2.name); + CuAssertTrue(tc, tc2.failed); + CuAssertTrue(tc, tc2.ran); + CompareAsserts(tc, "TestRun failed", "test should fail", tc2.message); +} + +/*-------------------------------------------------------------------------* + * CuSuite Test + *-------------------------------------------------------------------------*/ + +void TestCuSuiteInit(CuTest* tc) +{ + CuSuite ts; + CuSuiteInit(&ts); + CuAssertTrue(tc, ts.count == 0); + CuAssertTrue(tc, ts.failCount == 0); +} + +void TestCuSuiteNew(CuTest* tc) +{ + CuSuite* ts = CuSuiteNew(); + CuAssertTrue(tc, ts->count == 0); + CuAssertTrue(tc, ts->failCount == 0); +} + +void TestCuSuiteAddTest(CuTest* tc) +{ + CuSuite ts; + CuTest tc2; + + CuSuiteInit(&ts); + CuTestInit(&tc2, "MyTest", zTestFails); + + CuSuiteAdd(&ts, &tc2); + CuAssertTrue(tc, ts.count == 1); + + CuAssertStrEquals(tc, "MyTest", ts.list[0]->name); +} + +void TestCuSuiteAddSuite(CuTest* tc) +{ + CuSuite* ts1 = CuSuiteNew(); + CuSuite* ts2 = CuSuiteNew(); + + CuSuiteAdd(ts1, CuTestNew("TestFails1", zTestFails)); + CuSuiteAdd(ts1, CuTestNew("TestFails2", zTestFails)); + + CuSuiteAdd(ts2, CuTestNew("TestFails3", zTestFails)); + CuSuiteAdd(ts2, CuTestNew("TestFails4", zTestFails)); + + CuSuiteAddSuite(ts1, ts2); + CuAssertIntEquals(tc, 4, ts1->count); + + CuAssertStrEquals(tc, "TestFails1", ts1->list[0]->name); + CuAssertStrEquals(tc, "TestFails2", ts1->list[1]->name); + CuAssertStrEquals(tc, "TestFails3", ts1->list[2]->name); + CuAssertStrEquals(tc, "TestFails4", ts1->list[3]->name); +} + +void TestCuSuiteRun(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2, tc3, tc4; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestPasses", TestPasses); + CuTestInit(&tc3, "TestFails", zTestFails); + CuTestInit(&tc4, "TestFails", zTestFails); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteAdd(&ts, &tc3); + CuSuiteAdd(&ts, &tc4); + CuAssertTrue(tc, ts.count == 4); + + CuSuiteRun(&ts); + CuAssertTrue(tc, ts.count - ts.failCount == 2); + CuAssertTrue(tc, ts.failCount == 2); +} + +void TestCuSuiteSummary(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString summary; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestFails", zTestFails); + CuStringInit(&summary); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteSummary(&ts, &summary); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 1); + CuAssertStrEquals(tc, ".F\n\n", summary.buffer); +} + + +void TestCuSuiteDetails_SingleFail(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* front; + const char* back; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestFails", zTestFails); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 1); + + front = "There was 1 failure:\n" + "1) TestFails: "; + back = "test should fail\n" + "\n!!!FAILURES!!!\n" + "Runs: 2 Passes: 1 Fails: 1\n"; + + CuAssertStrEquals(tc, back, details.buffer + strlen(details.buffer) - strlen(back)); + details.buffer[strlen(front)] = 0; + CuAssertStrEquals(tc, front, details.buffer); +} + + +void TestCuSuiteDetails_SinglePass(CuTest* tc) +{ + CuSuite ts; + CuTest tc1; + CuString details; + const char* expected; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 1); + CuAssertTrue(tc, ts.failCount == 0); + + expected = + "OK (1 test)\n"; + + CuAssertStrEquals(tc, expected, details.buffer); +} + +void TestCuSuiteDetails_MultiplePasses(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* expected; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestPasses", TestPasses); + CuTestInit(&tc2, "TestPasses", TestPasses); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 0); + + expected = + "OK (2 tests)\n"; + + CuAssertStrEquals(tc, expected, details.buffer); +} + +void TestCuSuiteDetails_MultipleFails(CuTest* tc) +{ + CuSuite ts; + CuTest tc1, tc2; + CuString details; + const char* front; + const char* mid; + const char* back; + + CuSuiteInit(&ts); + CuTestInit(&tc1, "TestFails1", zTestFails); + CuTestInit(&tc2, "TestFails2", zTestFails); + CuStringInit(&details); + + CuSuiteAdd(&ts, &tc1); + CuSuiteAdd(&ts, &tc2); + CuSuiteRun(&ts); + + CuSuiteDetails(&ts, &details); + + CuAssertTrue(tc, ts.count == 2); + CuAssertTrue(tc, ts.failCount == 2); + + front = + "There were 2 failures:\n" + "1) TestFails1: "; + mid = "test should fail\n" + "2) TestFails2: "; + back = "test should fail\n" + "\n!!!FAILURES!!!\n" + "Runs: 2 Passes: 0 Fails: 2\n"; + + CuAssertStrEquals(tc, back, details.buffer + strlen(details.buffer) - strlen(back)); + CuAssert(tc, "Couldn't find middle", strstr(details.buffer, mid) != NULL); + details.buffer[strlen(front)] = 0; + CuAssertStrEquals(tc, front, details.buffer); +} + + +/*-------------------------------------------------------------------------* + * Misc Test + *-------------------------------------------------------------------------*/ + +void TestCuStrCopy(CuTest* tc) +{ + const char* old = "hello world"; + const char* newStr = CuStrCopy(old); + CuAssert(tc, "old is new", strcmp(old, newStr) == 0); +} + + +void TestCuStringAppendFormat(CuTest* tc) +{ + int i; + char* text = CuStrAlloc(301); /* long string */ + CuString* str = CuStringNew(); + for (i = 0 ; i < 300 ; ++i) + text[i] = 'a'; + text[300] = '\0'; + CuStringAppendFormat(str, "%s", text); + + /* buffer limit raised to HUGE_STRING_LEN so no overflow */ + + CuAssert(tc, "length of str->buffer is 300", 300 == strlen(str->buffer)); +} + +void TestFail(CuTest* tc) +{ + jmp_buf buf; + int pointReached = 0; + CuTest* tc2 = CuTestNew("TestFails", zTestFails); + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuFail(tc2, "hello world"); + pointReached = 1; + } + CuAssert(tc, "point was not reached", pointReached == 0); +} + +void TestAssertStrEquals(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, "hello", "world"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", "hello", "world"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expectedMsg, tc2->message); +} + +void TestAssertStrEquals_NULL(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_NULL", zTestFails); + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, NULL, NULL); + } + CuAssertTrue(tc, !tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_NULL failed", NULL, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", NULL, NULL); + } + CuAssertTrue(tc, !tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_NULL failed", NULL, tc2->message); +} + +void TestAssertStrEquals_FailNULLStr(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_FailNULLStr", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, "hello", NULL); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailNULLStr failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", "hello", NULL); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailNULLStr failed", expectedMsg, tc2->message); +} + +void TestAssertStrEquals_FailStrNULL(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertStrEquals_FailStrNULL", zTestFails); + + const char* expected = "expected but was "; + const char *expectedMsg = "some text: expected but was "; + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertStrEquals(tc2, NULL, "hello"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailStrNULL failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertStrEquals_Msg(tc2, "some text", NULL, "hello"); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals_FailStrNULL failed", expectedMsg, tc2->message); +} + +void TestAssertIntEquals(CuTest* tc) +{ + jmp_buf buf; + CuTest *tc2 = CuTestNew("TestAssertIntEquals", zTestFails); + const char* expected = "expected <42> but was <32>"; + const char* expectedMsg = "some text: expected <42> but was <32>"; + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertIntEquals(tc2, 42, 32); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertIntEquals failed", expected, tc2->message); + if (setjmp(buf) == 0) + { + CuAssertIntEquals_Msg(tc2, "some text", 42, 32); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertStrEquals failed", expectedMsg, tc2->message); +} + +void TestAssertDblEquals(CuTest* tc) +{ + jmp_buf buf; + double x = 3.33; + double y = 10.0 / 3.0; + CuTest *tc2 = CuTestNew("TestAssertDblEquals", zTestFails); + char expected[STRING_MAX]; + char expectedMsg[STRING_MAX]; + sprintf(expected, "expected <%lf> but was <%lf>", x, y); + sprintf(expectedMsg, "some text: expected <%lf> but was <%lf>", x, y); + + CuTestInit(tc2, "TestAssertDblEquals", TestPasses); + + CuAssertDblEquals(tc2, x, x, 0.0); + CuAssertTrue(tc, ! tc2->failed); + CuAssertTrue(tc, NULL == tc2->message); + + CuAssertDblEquals(tc2, x, y, 0.01); + CuAssertTrue(tc, ! tc2->failed); + CuAssertTrue(tc, NULL == tc2->message); + + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertDblEquals(tc2, x, y, 0.001); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertDblEquals failed", expected, tc2->message); + tc2->jumpBuf = &buf; + if (setjmp(buf) == 0) + { + CuAssertDblEquals_Msg(tc2, "some text", x, y, 0.001); + } + CuAssertTrue(tc, tc2->failed); + CompareAsserts(tc, "CuAssertDblEquals failed", expectedMsg, tc2->message); +} + +/*-------------------------------------------------------------------------* + * main + *-------------------------------------------------------------------------*/ + +CuSuite* CuGetSuite(void) +{ + CuSuite* suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, TestCuStringAppendFormat); + SUITE_ADD_TEST(suite, TestCuStrCopy); + SUITE_ADD_TEST(suite, TestFail); + SUITE_ADD_TEST(suite, TestAssertStrEquals); + SUITE_ADD_TEST(suite, TestAssertStrEquals_NULL); + SUITE_ADD_TEST(suite, TestAssertStrEquals_FailStrNULL); + SUITE_ADD_TEST(suite, TestAssertStrEquals_FailNULLStr); + SUITE_ADD_TEST(suite, TestAssertIntEquals); + SUITE_ADD_TEST(suite, TestAssertDblEquals); + + SUITE_ADD_TEST(suite, TestCuTestNew); + SUITE_ADD_TEST(suite, TestCuTestInit); + SUITE_ADD_TEST(suite, TestCuAssert); + SUITE_ADD_TEST(suite, TestCuAssertPtrEquals_Success); + SUITE_ADD_TEST(suite, TestCuAssertPtrEquals_Failure); + SUITE_ADD_TEST(suite, TestCuAssertPtrNotNull_Success); + SUITE_ADD_TEST(suite, TestCuAssertPtrNotNull_Failure); + SUITE_ADD_TEST(suite, TestCuTestRun); + + SUITE_ADD_TEST(suite, TestCuSuiteInit); + SUITE_ADD_TEST(suite, TestCuSuiteNew); + SUITE_ADD_TEST(suite, TestCuSuiteAddTest); + SUITE_ADD_TEST(suite, TestCuSuiteAddSuite); + SUITE_ADD_TEST(suite, TestCuSuiteRun); + SUITE_ADD_TEST(suite, TestCuSuiteSummary); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_SingleFail); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_SinglePass); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_MultiplePasses); + SUITE_ADD_TEST(suite, TestCuSuiteDetails_MultipleFails); + + return suite; +} diff --git a/dynarrc/common.h b/dynarrc/common.h index bfdd02a..dadddd2 100644 --- a/dynarrc/common.h +++ b/dynarrc/common.h @@ -73,4 +73,22 @@ __inline void int_swap(unsigned int *var1, unsigned int *var2) { } +#ifndef TYPED_NAME +// prefix the name with the type +#define TYPED_NAME(type, name ) TOKEN_PASTE(type, name) +#endif + +// inlining +#if defined(_MSC_VER) + +// inlining +#define INLINE _inline /* use _inline (VC++ specific) */ +// #define INLINE __forceinline /* use __forceinline (VC++ specific) */ +//#elif __GNUC__ && !__GNUC_STDC_INLINE__ +//#define INLINE inline +#else +#define INLINE inline /* use standard inline */ +#endif + + #endif // __dynarr_common_h__ \ No newline at end of file diff --git a/dynarrc/dynarr.h b/dynarrc/dynarr.h index 68c9467..6ad5641 100644 --- a/dynarrc/dynarr.h +++ b/dynarrc/dynarr.h @@ -4,19 +4,23 @@ #include #include -//#define MAXSEG 5 -//#define DYNARR_DATA_TYPE int -//#define TYPED_NAME(name) TOKEN_PASTE(DYNARR_DATA_TYPE, name) -/* Assuming MAXSEG is defined. - Size of each block of the dynamic array. - Must be a positive integer.*/ -/* Assuming DYNARR_DATA_TYPE is defined. - The data type of the array. - Must be a valid one-word type without space, *, etc. (use typedef if necessary) - */ +#ifdef __cplusplus +extern "C"{ +#endif + + //#define MAXSEG 5 + //#define DYNARR_DATA_TYPE int + //#define TYPED_NAME(name) TOKEN_PASTE(DYNARR_DATA_TYPE, name) + /* Assuming MAXSEG is defined. + Size of each block of the dynamic array. + Must be a positive integer.*/ + /* Assuming DYNARR_DATA_TYPE is defined. + The data type of the array. + Must be a valid one-word type without space, *, etc. (use typedef if necessary) + */ #ifndef MAXSEG -// #pragma message("MAXSEG must be defined before including " __FILE__) -// must be pow of 2 + // #pragma message("MAXSEG must be defined before including " __FILE__) + // must be pow of 2 #define MAXSEG 1024 #elif MAXSEG <= 0 #pragma message("MAXSEG has non positive value: " MAXSEG) @@ -25,523 +29,43 @@ #endif -// everything is fine -#ifndef __dynarr_only_once__ -#define __dynarr_only_once__ - - -// the struct FreeSegNode will be used multiple times, so we do not want to redefine it -struct FreeSegNode{ - int index; - struct FreeSegNode* next; -}; -typedef struct FreeSegNode FreeSegNode; - - - -#define _FreeSegNodeMalloc() \ - ( (struct FreeSegNode*) malloc(sizeof(struct FreeSegNode)) ) -// Swaps two 32-bit intergers without using temporary variables -#define _SEG_ARR_INT_SWAP(var1, var2) (\ - (var1) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ), \ - (var2) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ), \ - (var1) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ) ) -// Given two lists A and B, moves the head of A in front of the -// head of B. Head of A must be non-null. -// -// Before: -// A-->1-2-3-4-5 -// B-->a-b-c-d-e -// After: -// A-->2-3-4-5 -// B-->1-a-b-c-d-e -// -#define _SEG_ARR_MOVE_LIST_HEAD(listFrom, listTo) (\ - _SEG_ARR_INT_SWAP( listFrom->next, listTo), \ - _SEG_ARR_INT_SWAP( listFrom, listTo ) \ - ) - -#ifndef TYPED_NAME -// prefix the name with the type -#define TYPED_NAME(type, name ) TOKEN_PASTE(type, name) -#endif - -#if defined(_MSC_VER) - -// inlining -#define INLINE _inline /* use _inline (VC++ specific) */ -// #define INLINE __forceinline /* use __forceinline (VC++ specific) */ -//#elif __GNUC__ && !__GNUC_STDC_INLINE__ -//#define INLINE inline -#else -#define INLINE inline /* use standard inline */ -#endif - -#endif // __dynarr_only_once__ - - - - -/* The segment structure. These are the nodes of the linked list */ -#define DYNARR_SEG_TYPE(type) TYPED_NAME(type, Sseg) -typedef struct { - int index; // my position - int nextIndex; // next node's position - DYNARR_DATA_TYPE data; -}DYNARR_SEG_TYPE(DYNARR_DATA_TYPE); - -// true if the index is 0 -#define DYNARR_SEG_NULL(value_seg) ( (value_seg).index == EMPTY_INDEX ) -#define DYNARR_SEG_NOT_NULL(value_seg) ( (value_seg).index != EMPTY_INDEX ) -#define MAKE_DYNARR_SEG_NULL(value_seg) ( (value_seg).index = EMPTY_INDEX ) - + // everything is fine +#include "dynarrc.freeseglistonce.h" -/* The dynamic array data structure */ -#define DYNARR_STATE(type) TYPED_NAME(type, DynArr) -typedef struct{ - ////////// basics ////////// - //unsigned int MaxSeg; - /* Base-2 log */ - unsigned int LogMaxSeg; - /* MAXSEG-1; MAXSEG must be a power of 2 */ - unsigned int MaxSegRemainderBitMask; + // state variables +#include "dynarrc.vars.h" - DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)* pSegArr; - //real_t* pSegNextArr; - int iInsertPos; - /////////////////// Free nodes list //////////////// - struct FreeSegNode *pFreeSegList, *pFreeSegInvalidList; - int iSizeOfFreeSegList; - struct FreeSegNode* pTempFreeNode1, *pTempFreeNode2; - ////////////// temporaries ////////////// - int iTempIndex1, iTempIndex2; - DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) tempSeg1; - DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) emptySeg; - //////////// Segment banks //////////// - DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)** pSegBanksArr; - int* pSegBankSizeArr; - int* pSegBankIndexLimitArr; - int NumSegBanks; - int MaxSegBanks; - int SegBankAllocViolation; -} DYNARR_STATE(DYNARR_DATA_TYPE); -#pragma message(TO_STRING(DYNARR_STATE(DYNARR_DATA_TYPE))) -// dynarr variable name; contains all state variables -#define DYNARR_VARS(type) TYPED_NAME(type, Vars) - -// create a global dynarr struct containing all state variables for given type -#define SEG_ARR_CREATE(type) \ - DYNARR_STATE(type) DYNARR_VARS(type); - -// use the global dynarr struct containing all state variables for given type -#define SEG_ARR_USE(type) \ - extern SEG_ARR_CREATE(type); - -/* Declare state variables to be used by functions below */ -SEG_ARR_USE(DYNARR_DATA_TYPE); - - -/* Shortcuts to important variables */ -#define LOGMAXSEG(type) MEMBER(DYNARR_VARS(type),.,LogMaxSeg) -#pragma message(TO_STRING(LOGMAXSEG(DYNARR_DATA_TYPE))) -#define MAXSEG_REMAINDER_BITMASK(type) MEMBER(DYNARR_VARS(type),.,MaxSegRemainderBitMask) -#pragma message(TO_STRING(MAXSEG_REMAINDER_BITMASK(DYNARR_DATA_TYPE))) -#define SEG_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegArr) -#pragma message(TO_STRING(SEG_ARR(DYNARR_DATA_TYPE))) -#define SEG_INSERT_POS(type) MEMBER(DYNARR_VARS(type),.,iInsertPos) -#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) -#define FREESEG_LIST(type) MEMBER(DYNARR_VARS(type),.,pFreeSegList) -#pragma message(TO_STRING(FREESEG_LIST(DYNARR_DATA_TYPE))) -#define FREESEG_INVALID_LIST(type) MEMBER(DYNARR_VARS(type),.,pFreeSegInvalidList) -#pragma message(TO_STRING(FREESEG_INVALID_LIST(DYNARR_DATA_TYPE))) -#define FREESEG_LIST_SIZE(type) DYNARR_VARS(type).iSizeOfFreeSegList -#pragma message(TO_STRING(FREESEG_LIST_SIZE(DYNARR_DATA_TYPE))) -#define TEMP_FREESEGNODE_1(type) DYNARR_VARS(type).pTempFreeNode1 -#pragma message(TO_STRING(TEMP_FREESEGNODE_1(DYNARR_DATA_TYPE))) -#define TEMP_FREESEGNODE_2(type) DYNARR_VARS(type).pTempFreeNode2 -#pragma message(TO_STRING(TEMP_FREESEGNODE_2(DYNARR_DATA_TYPE))) -#define TEMP_INDEX_1(type) MEMBER(DYNARR_VARS(type),.,iTempIndex1) -#pragma message(TO_STRING(TEMP_INDEX_1(DYNARR_DATA_TYPE))) -#define TEMP_INDEX_2(type) MEMBER(DYNARR_VARS(type),.,iTempIndex2) -#pragma message(TO_STRING(TEMP_INDEX_2(DYNARR_DATA_TYPE))) -#define TEMP_SEG_1(type) DYNARR_VARS(type).iTempIndex1 -#pragma message(TO_STRING(TEMP_SEG_1(DYNARR_DATA_TYPE))) -#define NULL_SEG(type) DYNARR_VARS(type).emptySeg -#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) -#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) -#define SEG_BANK_ALLOC_VIOLATION(type) DYNARR_VARS(type).SegBankAllocViolation -#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) -// maximum number of segment banks -// this should be a very big number -// this number should never be reached -#define MAX_SEG_BANKS(type) MEMBER(DYNARR_VARS(type),.,MaxSegBanks) - -// array containing size (# of segments) of each segment bank -#define SEG_BANK_SIZE_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBankSizeArr) - -// array containing last valid index of each segment bank -#define SEG_BANK_INDEX_LIMIT_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBankIndexLimitArr) - -// Number of active segment banks -#define NUM_SEG_BANKS(type) MEMBER(DYNARR_VARS(type),.,NumSegBanks) -#define CURRENT_SEG_BANK(type) (NUM_SEG_BANKS(type) - 1) -// actual segment banks -#define SEG_BANKS_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBanksArr) - - - -// external declarations for allocating/resizing blocks + // external declarations for allocating/resizing blocks #define SEG_ARR_ALLOC_NEXT_FUNC(type) TYPED_NAME(type, _seg_bank_alloc_next) #define SEG_ARR_INC_MAX_FUNC(type) TYPED_NAME(type, _seg_bank_increase_max) -// early declarations -extern int SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)(); -extern int SEG_ARR_INC_MAX_FUNC(DYNARR_DATA_TYPE)(); - - -#define EMPTY_INDEX 0 -#define EMPTY_BYTE 0 -#define SEG_INSERT_POS_BEGIN 1 - -// segment banks -#if _REGION_ - - -// coordinates in the 2-D segment allocation -#define BANK_INDEX_FROM_SEG_INDEX(type, index) \ - ( ((unsigned int)(index)) >> LOG_MAXSEG(type) ) - -#define BANK_FROM_SEG_INDEX(type, index) SEG_BANKS_ARR[BANK_INDEX_FROM_SEG_INDEX(type, index)] -#define SLOT_FROM_SEG_INDEX(type, index) (((unsigned int)(index)) & MAXSEG_REMAINDER_BITMASK(type)) - -// pointer to the segment -#define PTR_SEG_FROM_INDEX(type, index) \ - (BANK_FROM_SEG_INDEX(type, index) + SLOT_FROM_SEG_INDEX(type, index) ) -#endif +#define SEG_ARR_ALLOC_SEG_FUNC(type) TYPED_NAME(type, _seg_arr_alloc_seg) + // early declarations + extern int SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)(); + extern int SEG_ARR_INC_MAX_FUNC(DYNARR_DATA_TYPE)(); + extern DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) SEG_ARR_ALLOC_SEG_FUNC(DYNARR_DATA_TYPE)(); -// Free segment list methods -#if _REGION_ -// returns index -#define _SEG_ARR_FREE_LIST_ADD_VALIDLIST(type, value_seg) (\ - (!FREESEG_LIST(type))\ - ?(\ - FREESEG_LIST(type) = _FreeSegNodeMalloc(), \ - /*assert(FREESEG_LIST(type) != NULL );*/ \ - FREESEG_LIST(type)->next = NULL, \ - FREESEG_LIST(type)->index = ((value_seg).index) \ - ) : (\ - TEMP_FREESEGNODE_1(type) = _FreeSegNodeMalloc(), \ - /*assert(pTempFreeNode1 != NULL );*/ \ - TEMP_FREESEGNODE_1(type)->next = FREESEG_LIST(type); \ - FREESEG_LIST(type) = TEMP_FREESEGNODE_1(type); \ - FREESEG_LIST(type)->index = ((value_seg).index) \ - ) \ - ) + // Free segment list methods +#include "dynarrc.freeseglistmethods.h" -// Algorithm: -// If (an invalid node exists) Then -// move it to the front of valid list -// set its index as the index of value_seg -// Else -// Allocate new node in the valid list -// -#define _SEG_ARR_FREE_LIST_ADD(type, value_seg) (\ - ( FREESEG_INVALID_LIST(type) ) \ - ? ( \ - _SEG_ARR_MOVE_LIST_HEAD( FREESEG_INVALID_LIST(type), FREESEG_LIST(type) ), \ - FREESEG_LIST(type)->index = ((value_seg).index) \ - ) \ - : ( _SEG_ARR_FREE_LIST_ADD_VALIDLIST_FUNC(type)(value_seg) ) \ - ) + /* DynArr core methods*/ +#include "dynarrc.coremethods.h" + /* Segment access methods */ +#include "dynarrc.segmentmethods.h" -#define _SEG_ARR_REMOVE_LIST_HEAD(type, list) (\ - TEMP_FREESEGNODE_1(type) = list, \ - list = list->next, \ - FREE_SAFE( TEMP_FREESEGNODE_1(type) ) )\ -// Algorithm: -// If (a valid node exists) Then -// output its index, and -// move it to the front of invalid list -// Else -// output null index -// -#define _SEG_ARR_FREE_LIST_GRAB_INDEX(type, value_seg) (\ - ( FREESEG_LIST(type) ) ?(\ - (value_seg).index = FREESEG_LIST(type)->index, \ - (value_seg).nextIndex = EMPTY_INDEX, \ - _SEG_ARR_MOVE_LIST_HEAD( type, FREESEG_LIST(type), FREESEG_INVALID_LIST(type) ), \ - (value_seg) \ - ):(\ - MAKE_DYNARR_SEG_NULL(value_seg), \ - (value_seg) \ - ) )\ + /*------- Seg banks methods -------------*/ +#include "dynarrc.segbankmethods.h" -#define _SEG_ARR_FREE_LIST_CLEANUP(type) {\ - while( FREESEG_LIST(type) ) {\ - _SEG_ARR_REMOVE_LIST_HEAD(type, FREESEG_LIST(type)); \ - } \ - while( FREESEG_INVALID_LIST(type) ) {\ - _SEG_ARR_REMOVE_LIST_HEAD(type, FREESEG_INVALID_LIST(type)); \ - } \ -} \ + /* Finally, the interface used by clients */ +#include "dynarrc.interface.h" +#ifdef __cplusplus +} // extern "C" #endif -/* DynArr methods*/ -#if _REGION_ - -// SEG_ARR_USE() and SEG_ARR_CREATE() has already been defined - -// initialize all state variables in the global dynarr struct for given type -#define SEG_ARR_INIT(type) \ - /*MaxSeg should be already assigned */ \ - assert(MAXSEG > 0 ); \ - LOGMAXSEG(type) = (unsigned int) (log(MAXSEG+0.0f)/log(2.0f)); \ - MAXSEG_REMAINDER_BITMASK(type) = (unsigned int) (MAXSEG - 1); \ - NULL_SEG(type).index = NULL_SEG(type).nextIndex = EMPTY_INDEX; \ - /* seg-arr management */ \ - SEG_ARR(type) = ( DYNARR_SEG_TYPE(type) *) malloc( sizeof(DYNARR_SEG_TYPE(type) ) * MAXSEG ); \ - assert(SEG_ARR(type) != NULL ); \ - memset(SEG_ARR(type), 0, sizeof(DYNARR_SEG_TYPE(type)) * MAXSEG ); \ - SEG_INSERT_POS(type) = SEG_INSERT_POS_BEGIN; \ - /*------------------------------------*/ \ - /* multiple segment banks */ \ - /* In test mode, do not initalize MaxSegBanks here so that */ \ - /* it can be initialized by other code before calling SEG_BANKS_INIT() */ \ - /*if (!TestEnabled) MAX_SEG_BANKS(type) = 1; */ \ - NUM_SEG_BANKS(type) = 1; /* Default value */ \ - MAX_SEG_BANKS(type) = 1; /* Default value */ \ - SEG_BANK_ALLOC_VIOLATION(type) = 0; \ - /* segment banks*/ \ - SEG_BANKS_ARR(type) = (DYNARR_SEG_TYPE(type)**)malloc(MAX_SEG_BANKS(type) * sizeof(DYNARR_SEG_TYPE(type)*)); \ - memset(SEG_BANKS_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(DYNARR_SEG_TYPE(type)*)); \ - /* segment bank sizes*/ \ - SEG_BANK_SIZE_ARR(type) = (int*)malloc(MAX_SEG_BANKS(type) * sizeof(int)); \ - memset(SEG_BANK_SIZE_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(int)); \ - /* segment bank index limits */ \ - SEG_BANK_INDEX_LIMIT_ARR(type) = (int*)malloc(MAX_SEG_BANKS(type) * sizeof(int)); \ - memset(SEG_BANK_INDEX_LIMIT_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(int)); \ - /* first segment bacnk already allocated */ \ - SEG_BANKS_ARR(type)[0] = SEG_ARR(type); \ - SEG_BANK_SIZE_ARR(type)[0] = MAXSEG; \ - SEG_BANK_INDEX_LIMIT_ARR(type)[0] = MAXSEG - 1; \ - NUM_SEG_BANKS(type) = 1; - - -// cleanup all state variables in the global dynarr struct for given type -#define SEG_ARR_CLEANUP(type) \ - FREE_SAFE( SEG_ARR(type) ); \ - SEG_INSERT_POS(type) = SEG_INSERT_POS_BEGIN; \ - /*-------------------------------*/ \ - /* multiple segment banks */ \ - for(TEMP_INDEX_1(type) = 1; TEMP_INDEX_1(type) < NUM_SEG_BANKS(type); TEMP_INDEX_1(type)++){ \ - FREE_SAFE(SEG_BANKS_ARR(type)[TEMP_INDEX_1(type)]); \ - } \ - FREE_SAFE(SEG_BANKS_ARR(type)); \ - FREE_SAFE(SEG_BANK_SIZE_ARR(type)); \ - FREE_SAFE(SEG_BANK_INDEX_LIMIT_ARR(type)); \ - SEG_BANK_ALLOC_VIOLATION(type) = 0; \ - _SEG_ARR_FREE_LIST_CLEANUP(type); \ - -#endif // _REGION - -//#define SEG_ARR_EXISTS() ( pSegArr != NULL ) -//#define SEG_ARR_SIZE NUM_SEG_ARR_ITEMS - -#define SEG_ARR_SEG_NEXT_INDEX(type, value_seg) (PTR_SEG_FROM_INDEX(type, (value_seg).index)->nextIndex) -// segment allocation/free/access -#if 1 //_REGION_ -/* Accessor methods */ -#define SEG_ARR_GET_SEG(type, segIndex) \ - ( (segIndex) != EMPTY_INDEX && \ - (segIndex) >= 0 && \ - (segIndex) < SEG_INSERT_POS(type) )\ - ? ( (TEMP_SEG_1(type)).index = (segIndex),\ - TEMP_SEG_1(type).nextIndex = \ - (int) (SEG_ARR_SEG_NEXT_INDEX(type, TEMP_SEG_1(type))),\ - TEMP_SEG_1(type))\ - : NULL_SEG(type) - -#define SEG_ARR_FREE_SET(type, value_seg) \ - ( _SEG_ARR_FREE_LIST_ADD(type, (value_seg)), \ - /*TOTALSEGS_DECR(), */\ - SEG_ARR_SEG_NEXT_INDEX(type, (value_seg)) = EMPTY_INDEX, \ - (value_seg).index = (value_seg).nextIndex = EMPTY_INDEX \ - ) - -#define SEG_ARR_FREE_GET(type, value_seg) (\ - _SEG_ARR_FREE_LIST_GRAB_INDEX(type, (value_seg)), \ - (value_seg) \ - ) - -// should return NULL_SEG if alloc fails -#define SEG_ARR_ALLOC_SEG(type, value_seg) (\ - (SEG_BANK_ALLOC_VIOLATION(type)) \ - ? ((value_seg).index = (value_seg).nextIndex = EMPTY_INDEX, (value_seg) ) \ - : ( \ - (value_seg).index = SEG_INSERT_POS(type), \ - (value_seg).nextIndex = EMPTY_INDEX, \ - (SEG_INSERT_POS(type) >= SEG_BANK_INDEX_LIMIT_ARR(type)[NUM_SEG_BANKS(type)-1]) \ - ? /* last index filled. allocate more banks. */ \ - SEG_ARR_ALLOC_NEXT_FUNC(type) \ - ? /* ok */ (void) 0 \ - : /* further alloc not possible */ (\ - SEG_BANK_ALLOC_VIOLATION(type) = 1, \ - printf("\nFatal error: No more segment allocation possible." \ - "\n\tSegment index: %d, Last possible index: %d " \ - "NumSegBanks: %d, MaxSegBanks: %d " \ - "\n\tFile: %s\n\tLine: %d\n", \ - SEG_INSERT_POS(type), SEG_BANK_INDEX_LIMIT_ARR(type)[CURRENT_SEG_BANK(type)], \ - NUM_SEG_BANKS(type), MAX_SEG_BANKS(type), \ - __FILE__, __LINE__) \ - ) \ - : /* last index not filled */ SEG_INSERT_POS(type)++, \ - (value_seg)\ - ) \ - ) \ - -#endif // _REGION_ - - -/*---------------------------------------*/ -/*------- Seg banks methods -------------*/ - - -// when maximum number of segment banks is reached, -// double MaxSegBanks and -// reallocate the bookkeeping machinery -// returns 0 if bad, 1 if ok -static INLINE int SEG_ARR_INC_MAX_FUNC(DYNARR_DATA_TYPE)(){ - void* pVoid; - int bSuccess = 1; - int prevMaxSegBanks = MAX_SEG_BANKS(DYNARR_DATA_TYPE); - // new limit on number of segment banks - MAX_SEG_BANKS(DYNARR_DATA_TYPE) <<= 1; - - // realloc - if (pVoid = realloc(SEG_BANKS_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*))){ - SEG_BANKS_ARR(DYNARR_DATA_TYPE) = (DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)**)pVoid; - memset(SEG_BANKS_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, - (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*)); - } - else { - printf("\nFatal error: Failed to increase the Maximum number of segment banks." - "\n\tFile: %s\n\tLine: %d\n", - __FILE__, __LINE__); - return 0; - } - - if (pVoid = realloc(SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(int))){ - SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE) = (int*)pVoid; - memset(SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, - (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(int)); - } - else { - printf("\nFatal error: Failed to increase the Maximum number of segment banks." - "\n\tFile: %s\n\tLine: %d\n", - __FILE__, __LINE__); - return 0; - } - - if (pVoid = realloc(SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(int))){ - SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE) = (int*)pVoid; - memset(SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, - (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(int)); - } - else { - printf("\nFatal error: Failed to increase the Maximum number of segment banks." - "\n\tFile: %s\n\tLine: %d\n", - __FILE__, __LINE__); - return 0; - } - - // ok - return 1; - } - -// -// allocate next segment bank and place iInsertPos in appropriate value -// -static INLINE int SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)(){ - // shall we also alloc gpu with cpu? - int bAllocGpu = 0; - - int numElems = MAXSEG, - round = 0, - iHypotheticalTotalSegsUptoLastActiveBank = 0; - DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)* ptr; - int bCpuGpuAllocDone = 0; - - //assert(NumSegBanks < MAX_SEG_BANKS); - if (NUM_SEG_BANKS(DYNARR_DATA_TYPE) >= MAX_SEG_BANKS(DYNARR_DATA_TYPE)) { - // increase limit on the number of segment banks - if (!SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)()){ - // no futher alloc possible - SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) = 1; - - printf("\nFatal error: Maximum number of segment banks is reached." - "\n\tFile: %s\n\tLine: %d\n", - __FILE__, __LINE__); - return 0; - } - else{ - // great, it is possible to have more segment banks - // continue - } - } - - // ok, lets try to allocate one more segment bank - do{ - // cpu alloc - do{ - numElems >>= (round++); - assert(numElems % 4 == 0); // must be a multiple of 4 - - ptr = (DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*)malloc(numElems * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE))); - } while (numElems > 1 && ptr == NULL); - assert(ptr != NULL); - if (ptr == NULL){ - // no futher alloc possible - SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) = 1; - - printf("\nFatal error: Failed to allocate next segment bank" - "\n\tFile: %s\n\tLine: %d\n", __FILE__, __LINE__); - return 0; - } - - // ok in cpu - SEG_BANKS_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = ptr; - - // update the size of the bank - // it is used when allocating bank in gpu - SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = numElems; - - // now allocate corresponding bank in gpu - bCpuGpuAllocDone = 1; - } while (bCpuGpuAllocDone == 0); - - // great - // initialize everything to zero, this makes all segments initially null - memset(ptr, 0, numElems * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE))); - iHypotheticalTotalSegsUptoLastActiveBank = NUM_SEG_BANKS(DYNARR_DATA_TYPE) * MAXSEG; - // pretend that each segment bank is of size MaxSeg - SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = (iHypotheticalTotalSegsUptoLastActiveBank - 1) + numElems; - - // finally - SEG_INSERT_POS(DYNARR_DATA_TYPE) = iHypotheticalTotalSegsUptoLastActiveBank; - NUM_SEG_BANKS(DYNARR_DATA_TYPE)++; - - return 1; -} - -// done - - - - diff --git a/dynarrc/dynarrc.coremethods.h b/dynarrc/dynarrc.coremethods.h new file mode 100644 index 0000000..de178c1 --- /dev/null +++ b/dynarrc/dynarrc.coremethods.h @@ -0,0 +1,61 @@ + +// create a global dynarr struct containing all state variables for given type +#define SEG_ARR_CREATE(type) \ + DYNARR_STATE(type) DYNARR_VARS(type); + +// use the global dynarr struct containing all state variables for given type +#define SEG_ARR_USE(type) \ + extern SEG_ARR_CREATE(type); + +// initialize all state variables in the global dynarr struct for given type +#define SEG_ARR_INIT(type) \ + /*MaxSeg should be already assigned */ \ + assert(MAXSEG > 0 ); \ + LOGMAXSEG(type) = (unsigned int) (log(MAXSEG+0.0f)/log(2.0f)); \ + MAXSEG_REMAINDER_BITMASK(type) = (unsigned int) (MAXSEG - 1); \ + NULL_SEG(type).index = NULL_SEG(type).nextIndex = EMPTY_INDEX; \ + /* seg-arr management */ \ + SEG_ARR(type) = ( DYNARR_SEG_TYPE(type) *) malloc( sizeof(DYNARR_SEG_TYPE(type) ) * MAXSEG ); \ + assert(SEG_ARR(type) != NULL ); \ + memset(SEG_ARR(type), 0, sizeof(DYNARR_SEG_TYPE(type)) * MAXSEG ); \ + SEG_INSERT_POS(type) = SEG_INSERT_POS_BEGIN; \ + /*------------------------------------*/ \ + /* multiple segment banks */ \ + /* In test mode, do not initalize MaxSegBanks here so that */ \ + /* it can be initialized by other code before calling SEG_BANKS_INIT() */ \ + /*if (!TestEnabled) MAX_SEG_BANKS(type) = 1; */ \ + MAX_SEG_BANKS(type) = 1; /* Default value */ \ + TOTAL_SEGS(type) = 0; /* Default value */ \ + SEG_BANK_ALLOC_VIOLATION(type) = 0; \ + /* segment banks*/ \ + SEG_BANKS_ARR(type) = (DYNARR_SEG_TYPE(type)**)malloc(MAX_SEG_BANKS(type) * sizeof(DYNARR_SEG_TYPE(type)*)); \ + memset(SEG_BANKS_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(DYNARR_SEG_TYPE(type)*)); \ + /* segment bank sizes*/ \ + SEG_BANK_SIZE_ARR(type) = (int*)malloc(MAX_SEG_BANKS(type) * sizeof(int)); \ + memset(SEG_BANK_SIZE_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(int)); \ + /* segment bank index limits */ \ + SEG_BANK_INDEX_LIMIT_ARR(type) = (int*)malloc(MAX_SEG_BANKS(type) * sizeof(int)); \ + memset(SEG_BANK_INDEX_LIMIT_ARR(type), 0, MAX_SEG_BANKS(type) * sizeof(int)); \ + /* first segment bacnk already allocated */ \ + SEG_BANKS_ARR(type)[0] = SEG_ARR(type); \ + SEG_BANK_SIZE_ARR(type)[0] = MAXSEG; \ + SEG_BANK_INDEX_LIMIT_ARR(type)[0] = MAXSEG - 1; \ + NUM_SEG_BANKS(type) = 1; + + +// cleanup all state variables in the global dynarr struct for given type +#define SEG_ARR_CLEANUP(type) \ + FREE_SAFE( SEG_ARR(type) ); \ + SEG_INSERT_POS(type) = SEG_INSERT_POS_BEGIN; \ + /*-------------------------------*/ \ + /* multiple segment banks */ \ + for(TEMP_INDEX_1(type) = 1; TEMP_INDEX_1(type) < NUM_SEG_BANKS(type); TEMP_INDEX_1(type)++){ \ + FREE_SAFE(SEG_BANKS_ARR(type)[TEMP_INDEX_1(type)]); \ + } \ + NUM_SEG_BANKS(type) = 0; \ + FREE_SAFE(SEG_BANKS_ARR(type)); \ + FREE_SAFE(SEG_BANK_SIZE_ARR(type)); \ + FREE_SAFE(SEG_BANK_INDEX_LIMIT_ARR(type)); \ + SEG_BANK_ALLOC_VIOLATION(type) = 0; \ + _SEG_ARR_FREE_LIST_CLEANUP(type); \ + TOTAL_SEGS(type) = 0; diff --git a/dynarrc/dynarrc.freeseglistmethods.h b/dynarrc/dynarrc.freeseglistmethods.h new file mode 100644 index 0000000..413eda5 --- /dev/null +++ b/dynarrc/dynarrc.freeseglistmethods.h @@ -0,0 +1,71 @@ +// returns index +#define _SEG_ARR_FREE_LIST_ADD_VALIDLIST(type, value_seg) \ +do{\ + if(!FREESEG_LIST(type)){ \ + FREESEG_LIST(type) = _FreeSegNodeMalloc(); \ + /*assert(FREESEG_LIST(type) != NULL );*/ \ + FREESEG_LIST(type)->next = NULL; \ + FREESEG_LIST(type)->index = (value_seg).index; \ + } else{ \ + TEMP_FREESEGNODE_1(type) = _FreeSegNodeMalloc(); \ + /*assert(pTempFreeNode1 != NULL );*/ \ + TEMP_FREESEGNODE_1(type)->next = FREESEG_LIST(type); \ + FREESEG_LIST(type) = TEMP_FREESEGNODE_1(type); \ + FREESEG_LIST(type)->index = ((value_seg).index) ; \ + } \ +}while(0); + +// Algorithm: +// If (an invalid node exists) Then +// move it to the front of valid list +// set its index as the index of value_seg +// Else +// Allocate new node in the valid list +// +#define _SEG_ARR_FREE_LIST_ADD(type, value_seg) do{\ + /* check if we already have some previously-allocated memory */ \ + if( FREESEG_INVALID_LIST(type) ) {\ + /* yes */ \ + _SEG_ARR_MOVE_LIST_HEAD( FREESEG_INVALID_LIST(type), FREESEG_LIST(type) ); \ + FREESEG_LIST(type)->index = (value_seg).index ; \ + } \ + else{\ + _SEG_ARR_FREE_LIST_ADD_VALIDLIST(type, value_seg); \ + } \ +}while(0) + + +#define _SEG_ARR_REMOVE_LIST_HEAD(type, list) (\ + TEMP_FREESEGNODE_1(type) = list, \ + list = list->next, \ + FREE_SAFE( TEMP_FREESEGNODE_1(type) ) )\ + +// Algorithm: +// If (a valid node exists) Then +// output its index, and +// move it to the front of invalid list +// so that we can reuse its allocated-memory later +// Else +// output null index +// +#define _SEG_ARR_FREE_LIST_GRAB_INDEX(type, value_seg) do{\ + if( FREESEG_LIST(type) ) {\ + (value_seg).index = FREESEG_LIST(type)->index; \ + (value_seg).nextIndex = EMPTY_INDEX; \ + _SEG_ARR_MOVE_LIST_HEAD( FREESEG_LIST(type), FREESEG_INVALID_LIST(type) ); \ + }else{ \ + MAKE_DYNARR_SEG_NULL(value_seg); \ + } \ +}while(0) + + +#define _SEG_ARR_FREE_LIST_CLEANUP(type) do{\ + while( FREESEG_LIST(type) ) {\ + _SEG_ARR_REMOVE_LIST_HEAD(type, FREESEG_LIST(type)); \ + } \ + while( FREESEG_INVALID_LIST(type) ) {\ + _SEG_ARR_REMOVE_LIST_HEAD(type, FREESEG_INVALID_LIST(type)); \ + } \ +}while(0) + +#define _SEG_ARR_HAS_FREE_SEG(type) (FREESEG_LIST(type) != NULL) diff --git a/dynarrc/dynarrc.freeseglistonce.h b/dynarrc/dynarrc.freeseglistonce.h new file mode 100644 index 0000000..337cd3e --- /dev/null +++ b/dynarrc/dynarrc.freeseglistonce.h @@ -0,0 +1,38 @@ +#ifndef __dynarr_only_once__ +#define __dynarr_only_once__ + + +// the struct FreeSegNode will be used multiple times, so we do not want to redefine it +struct FreeSegNode{ + int index; + struct FreeSegNode* next; +}; +typedef struct FreeSegNode FreeSegNode; + + + +#define _FreeSegNodeMalloc() \ + ( (struct FreeSegNode*) malloc(sizeof(struct FreeSegNode)) ) +// Swaps two 32-bit intergers without using temporary variables +#define _SEG_ARR_INT_SWAP(var1, var2) (\ + (var1) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ), \ + (var2) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ), \ + (var1) = (FreeSegNode*) (((int) (void*) var1) ^ ((int) (void*) var2) ) ) +// Given two lists A and B, moves the head of A in front of the +// head of B. Head of A must be non-null. +// +// Before: +// A-->1-2-3-4-5 +// B-->a-b-c-d-e +// After: +// A-->2-3-4-5 +// B-->1-a-b-c-d-e +// +#define _SEG_ARR_MOVE_LIST_HEAD(listFrom, listTo) \ +do{\ + _SEG_ARR_INT_SWAP( listFrom->next, listTo); \ + _SEG_ARR_INT_SWAP( listFrom, listTo ); \ +}while(0) + + +#endif // __dynarr_only_once__ diff --git a/dynarrc/dynarrc.interface.h b/dynarrc/dynarrc.interface.h new file mode 100644 index 0000000..0aac3a4 --- /dev/null +++ b/dynarrc/dynarrc.interface.h @@ -0,0 +1,21 @@ +/* Main interface for array-based linked-list allocator */ + +// checks whether a segment is empty/NULL/unusable +#define segNull(seg) DYNARR_SEG_NULL(seg) +// checks whether a segment is not empty/NULL/unusable +#define segNotNull(seg) DYNARR_SEG_NOT_NULL(seg) +// checks whether there is an existing allocation error +#define isAllocError(type) SEG_BANK_ALLOC_VIOLATION(type) + +// allocate a new segment for given type +// returns an object of given type +// may be NULL_SEG if some problem occurs +// check using segNull(type, seg) macro +#define allocSeg(type) SEG_ARR_ALLOC_SEG_FUNC(type)() + +// release/free a segment for given type +#define freeSeg(type, seg) SEG_ARR_SEG_FREE_SET(type, seg) + +// segment at a particular index +// use segNull() to check validity of the returned segment +#define getSegAt(type, index) SEG_ARR_GET_SEG(type, index) diff --git a/dynarrc/dynarrc.segbankmethods.h b/dynarrc/dynarrc.segbankmethods.h new file mode 100644 index 0000000..8a5a674 --- /dev/null +++ b/dynarrc/dynarrc.segbankmethods.h @@ -0,0 +1,135 @@ +#ifndef DYNARR_DATA_TYPE +#pragma message("Error: DYNARR_DATA_TYPE not defined. " __FILE__) +#endif + +// when maximum number of segment banks is reached, +// double MaxSegBanks and +// reallocate the bookkeeping machinery +// returns 0 if bad, 1 if ok +static INLINE int SEG_ARR_INC_MAX_FUNC(DYNARR_DATA_TYPE)(){ + SEG_ARR_USE(DYNARR_DATA_TYPE); + void* pVoid; + int bSuccess = 1; + int prevMaxSegBanks = MAX_SEG_BANKS(DYNARR_DATA_TYPE); + // new limit on number of segment banks + // double from previous number + MAX_SEG_BANKS(DYNARR_DATA_TYPE) <<= 1; + + // realloc + if (pVoid = realloc(SEG_BANKS_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*))){ + SEG_BANKS_ARR(DYNARR_DATA_TYPE) = (DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)**)pVoid; + memset(SEG_BANKS_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, + (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*)); + } + else { + printf("\nFatal error: Failed to increase the Maximum number of segment banks." + "\n\tFile: %s\n\tLine: %d\n", + __FILE__, __LINE__); + return 0; + } + + if (pVoid = realloc(SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(int))){ + SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE) = (int*)pVoid; + memset(SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, + (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(int)); + } + else { + printf("\nFatal error: Failed to increase the Maximum number of segment banks." + "\n\tFile: %s\n\tLine: %d\n", + __FILE__, __LINE__); + return 0; + } + + if (pVoid = realloc(SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE), MAX_SEG_BANKS(DYNARR_DATA_TYPE) * sizeof(int))){ + SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE) = (int*)pVoid; + memset(SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE) + prevMaxSegBanks, 0, + (MAX_SEG_BANKS(DYNARR_DATA_TYPE) - prevMaxSegBanks) * sizeof(int)); + } + else { + printf("\nFatal error: Failed to increase the Maximum number of segment banks." + "\n\tFile: %s\n\tLine: %d\n", + __FILE__, __LINE__); + return 0; + } + + // ok + return 1; +} + +// +// allocate next segment bank and place iInsertPos in appropriate value +// +static INLINE int SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)(){ + SEG_ARR_USE(DYNARR_DATA_TYPE); + // shall we also alloc gpu with cpu? + int bAllocGpu = 0; + + int numElems = MAXSEG, + round = 0, + iHypotheticalTotalSegsUptoLastActiveBank = 0; + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)* ptr; + int bCpuGpuAllocDone = 0; + + //assert(NumSegBanks < MAX_SEG_BANKS); + if (NUM_SEG_BANKS(DYNARR_DATA_TYPE) >= MAX_SEG_BANKS(DYNARR_DATA_TYPE)) { + // increase limit on the number of segment banks + if (!SEG_ARR_INC_MAX_FUNC(DYNARR_DATA_TYPE)()){ + // no futher alloc possible + SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) = 1; + + printf("\nFatal error: Maximum number of segment banks is reached." + "\n\tFile: %s\n\tLine: %d\n", + __FILE__, __LINE__); + return 0; + } + else{ + // great, it is possible to have more segment banks + // continue + } + } + + // ok, lets try to allocate one more segment bank + do{ + // cpu alloc + // try allocating numElems segments + // if it fails, in next trial, try allocating half as many segments + do{ + numElems >>= (round++); + assert(numElems % 4 == 0); // must be a multiple of 4 + + ptr = (DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)*)malloc(numElems * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE))); + } while (numElems > 1 && ptr == NULL); + assert(ptr != NULL); + if (ptr == NULL){ + // no futher alloc possible + SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) = 1; + + printf("\nFatal error: Failed to allocate next segment bank" + "\n\tFile: %s\n\tLine: %d\n", __FILE__, __LINE__); + return 0; + } + + // ok in cpu + SEG_BANKS_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = ptr; + + // update the size of the bank + // it is used when allocating bank in gpu + SEG_BANK_SIZE_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = numElems; + + // now allocate corresponding bank in gpu + bCpuGpuAllocDone = 1; + } while (bCpuGpuAllocDone == 0); + + // great + // initialize everything to zero, this makes all segments initially null + memset(ptr, 0, numElems * sizeof(DYNARR_SEG_TYPE(DYNARR_DATA_TYPE))); + iHypotheticalTotalSegsUptoLastActiveBank = NUM_SEG_BANKS(DYNARR_DATA_TYPE) * MAXSEG; + // pretend that each segment bank is of size MaxSeg + SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE)] = (iHypotheticalTotalSegsUptoLastActiveBank - 1) + numElems; + + // finally + SEG_INSERT_POS(DYNARR_DATA_TYPE) = iHypotheticalTotalSegsUptoLastActiveBank; + NUM_SEG_BANKS(DYNARR_DATA_TYPE)++; + + return 1; +} diff --git a/dynarrc/dynarrc.segmentmethods.h b/dynarrc/dynarrc.segmentmethods.h new file mode 100644 index 0000000..97ffbd2 --- /dev/null +++ b/dynarrc/dynarrc.segmentmethods.h @@ -0,0 +1,96 @@ + +#define SEG_INSERT_POS_BEGIN 1 +#define EMPTY_INDEX 0 + + +// coordinates in the 2-D segment allocation +#define BANK_INDEX_FROM_SEG_INDEX(type, index) \ + ( ((unsigned int)(index)) >> LOGMAXSEG(type) ) + +#define BANK_FROM_SEG_INDEX(type, index) \ + SEG_BANKS_ARR(type)[BANK_INDEX_FROM_SEG_INDEX(type, index)] +#define SLOT_FROM_SEG_INDEX(type, index) \ + (((unsigned int)(index)) & MAXSEG_REMAINDER_BITMASK(type)) + +// pointer to the segment +#define PTR_SEG_FROM_INDEX(type, index) \ + (BANK_FROM_SEG_INDEX(type, index) + SLOT_FROM_SEG_INDEX(type, index) ) + + +#define SEG_ARR_SEG_NEXT_INDEX(type, value_seg) \ + (PTR_SEG_FROM_INDEX(type, (value_seg).index )->nextIndex) +// segment allocation/free/access +/* Accessor methods */ +#define SEG_ARR_GET_SEG(type, segIndex) \ + ( (segIndex) != EMPTY_INDEX && \ + (segIndex) >= 0 && \ + (segIndex) < SEG_INSERT_POS(type) )\ + ? ( (TEMP_SEG_1(type)).index = (segIndex),\ + TEMP_SEG_1(type).nextIndex = \ + (int) (SEG_ARR_SEG_NEXT_INDEX(type, TEMP_SEG_1(type))),\ + TEMP_SEG_1(type))\ + : NULL_SEG(type) + +#define SEG_ARR_SEG_FREE_SET(type, value_seg) \ +do{ \ + _SEG_ARR_FREE_LIST_ADD(type, value_seg ); \ + TOTAL_SEGS(type)--; \ + SEG_ARR_SEG_NEXT_INDEX(type, value_seg ) = EMPTY_INDEX; \ + (value_seg).index = (value_seg).nextIndex = EMPTY_INDEX ; \ +}while(0); + + +// returns an available slot +// possibly recycled from a previously deleted segment +// returns NULL_SEG if alloc fails +static INLINE DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) SEG_ARR_ALLOC_SEG_FUNC(DYNARR_DATA_TYPE)() { + SEG_ARR_USE(DYNARR_DATA_TYPE); + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) seg; + + // if there is a free segment available, take it + _SEG_ARR_FREE_LIST_GRAB_INDEX(DYNARR_DATA_TYPE, seg); + if (DYNARR_SEG_NOT_NULL(seg)){ + // valid seg + TOTAL_SEGS(DYNARR_DATA_TYPE)++; + return seg; + } + // no free segments available + if (SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE)){ + /* Something bad happened */ + (TEMP_SEG_1(DYNARR_DATA_TYPE) = NULL_SEG(DYNARR_DATA_TYPE)); + return TEMP_SEG_1(DYNARR_DATA_TYPE); + } + else{ + /* do we need to allocate more banks? */ + if (SEG_INSERT_POS(DYNARR_DATA_TYPE) > SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE)[NUM_SEG_BANKS(DYNARR_DATA_TYPE) - 1]) { + /* Yes: alloc a new bank */ + /* call function, and see return value */ + if (SEG_ARR_ALLOC_NEXT_FUNC(DYNARR_DATA_TYPE)() == 0){ + /* next-bank-allocation failed */ + SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) = 1; + printf("nFatal error: No more segment allocation possible." + "ntSegment index: %d, Last possible index: %d " + "NumSegBanks: %d, MaxSegBanks: %d " + "ntFile: %sntLine: %dn", + SEG_INSERT_POS(DYNARR_DATA_TYPE), + SEG_BANK_INDEX_LIMIT_ARR(DYNARR_DATA_TYPE)[CURRENT_SEG_BANK(DYNARR_DATA_TYPE)], + NUM_SEG_BANKS(DYNARR_DATA_TYPE), + MAX_SEG_BANKS(DYNARR_DATA_TYPE), + __FILE__, __LINE__); + TEMP_SEG_1(DYNARR_DATA_TYPE) = NULL_SEG(DYNARR_DATA_TYPE); + } + } + /* ready for insert, see if the coast is clear */ + if (SEG_BANK_ALLOC_VIOLATION(DYNARR_DATA_TYPE) == 0){ + /* insert a new segment in the current bank */ + TEMP_SEG_1(DYNARR_DATA_TYPE).index = SEG_INSERT_POS(DYNARR_DATA_TYPE); + TEMP_SEG_1(DYNARR_DATA_TYPE).nextIndex = EMPTY_INDEX; + SEG_INSERT_POS(DYNARR_DATA_TYPE)++; + TOTAL_SEGS(DYNARR_DATA_TYPE)++; + } + /* finally, return*/ + return TEMP_SEG_1(DYNARR_DATA_TYPE); + } +} + + diff --git a/dynarrc/dynarrc.vars.h b/dynarrc/dynarrc.vars.h new file mode 100644 index 0000000..3c7b38b --- /dev/null +++ b/dynarrc/dynarrc.vars.h @@ -0,0 +1,103 @@ + +/* The segment structure. These are the nodes of the linked list */ +#define DYNARR_SEG_TYPE(type) TYPED_NAME(type, Sseg) +typedef struct { + int index; // my position + int nextIndex; // next node's position + DYNARR_DATA_TYPE data; +}DYNARR_SEG_TYPE(DYNARR_DATA_TYPE); + +// true if the index is 0 +#define DYNARR_SEG_NULL(value_seg) ( (value_seg).index == EMPTY_INDEX ) +#define DYNARR_SEG_NOT_NULL(value_seg) ( (value_seg).index != EMPTY_INDEX ) +#define MAKE_DYNARR_SEG_NULL(value_seg) ( (value_seg).index = EMPTY_INDEX ) + + +/* The dynamic array data structure */ +#define DYNARR_STATE(type) TYPED_NAME(type, DynArr) +typedef struct{ + ////////// basics ////////// + //unsigned int MaxSeg; + /* Base-2 log */ + unsigned int LogMaxSeg; + /* MAXSEG-1; MAXSEG must be a power of 2 */ + unsigned int MaxSegRemainderBitMask; + + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)* pSegArr; + //real_t* pSegNextArr; + int iInsertPos; + /////////////////// Free nodes list //////////////// + struct FreeSegNode *pFreeSegList, *pFreeSegInvalidList; + int iSizeOfFreeSegList; + struct FreeSegNode* pTempFreeNode1, *pTempFreeNode2; + ////////////// temporaries ////////////// + int iTempIndex1, iTempIndex2; + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) tempSeg1; + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE) emptySeg; + //////////// Segment banks //////////// + DYNARR_SEG_TYPE(DYNARR_DATA_TYPE)** pSegBanksArr; + int* pSegBankSizeArr; + int* pSegBankIndexLimitArr; + int NumSegBanks; + int MaxSegBanks; + int SegBankAllocViolation; + + int TotalSegs; + +} DYNARR_STATE(DYNARR_DATA_TYPE); +#pragma message(TO_STRING(DYNARR_STATE(DYNARR_DATA_TYPE))) +// dynarr variable name; contains all state variables +#define DYNARR_VARS(type) TYPED_NAME(type, Vars) + + +/* Declare state variables to be used by functions below */ +// SEG_ARR_USE(DYNARR_DATA_TYPE); + + +/* Shortcuts to important variables */ +#define LOGMAXSEG(type) MEMBER(DYNARR_VARS(type),.,LogMaxSeg) +#pragma message(TO_STRING(LOGMAXSEG(DYNARR_DATA_TYPE))) +#define MAXSEG_REMAINDER_BITMASK(type) MEMBER(DYNARR_VARS(type),.,MaxSegRemainderBitMask) +#pragma message(TO_STRING(MAXSEG_REMAINDER_BITMASK(DYNARR_DATA_TYPE))) +#define SEG_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegArr) +#pragma message(TO_STRING(SEG_ARR(DYNARR_DATA_TYPE))) +#define SEG_INSERT_POS(type) MEMBER(DYNARR_VARS(type),.,iInsertPos) +#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) +#define FREESEG_LIST(type) MEMBER(DYNARR_VARS(type),.,pFreeSegList) +#pragma message(TO_STRING(FREESEG_LIST(DYNARR_DATA_TYPE))) +#define FREESEG_INVALID_LIST(type) MEMBER(DYNARR_VARS(type),.,pFreeSegInvalidList) +#pragma message(TO_STRING(FREESEG_INVALID_LIST(DYNARR_DATA_TYPE))) +#define FREESEG_LIST_SIZE(type) DYNARR_VARS(type).iSizeOfFreeSegList +#pragma message(TO_STRING(FREESEG_LIST_SIZE(DYNARR_DATA_TYPE))) +#define TEMP_FREESEGNODE_1(type) DYNARR_VARS(type).pTempFreeNode1 +#pragma message(TO_STRING(TEMP_FREESEGNODE_1(DYNARR_DATA_TYPE))) +#define TEMP_FREESEGNODE_2(type) DYNARR_VARS(type).pTempFreeNode2 +#pragma message(TO_STRING(TEMP_FREESEGNODE_2(DYNARR_DATA_TYPE))) +#define TEMP_INDEX_1(type) MEMBER(DYNARR_VARS(type),.,iTempIndex1) +#pragma message(TO_STRING(TEMP_INDEX_1(DYNARR_DATA_TYPE))) +#define TEMP_INDEX_2(type) MEMBER(DYNARR_VARS(type),.,iTempIndex2) +#pragma message(TO_STRING(TEMP_INDEX_2(DYNARR_DATA_TYPE))) +#define TEMP_SEG_1(type) MEMBER(DYNARR_VARS(type),.,tempSeg1) +#pragma message(TO_STRING(TEMP_SEG_1(DYNARR_DATA_TYPE))) +#define NULL_SEG(type) MEMBER(DYNARR_VARS(type),.,emptySeg) +#pragma message(TO_STRING(NULL_SEG(DYNARR_DATA_TYPE))) +#define TOTAL_SEGS(type) MEMBER(DYNARR_VARS(type),.,TotalSegs) +#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) +#define SEG_BANK_ALLOC_VIOLATION(type) MEMBER(DYNARR_VARS(type),.,SegBankAllocViolation) +#pragma message(TO_STRING(SEG_INSERT_POS(DYNARR_DATA_TYPE))) +// maximum number of segment banks +// this should be a very big number +// this number should never be reached +#define MAX_SEG_BANKS(type) MEMBER(DYNARR_VARS(type),.,MaxSegBanks) + +// array containing size (# of segments) of each segment bank +#define SEG_BANK_SIZE_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBankSizeArr) + +// array containing last valid index of each segment bank +#define SEG_BANK_INDEX_LIMIT_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBankIndexLimitArr) + +// Number of active segment banks +#define NUM_SEG_BANKS(type) MEMBER(DYNARR_VARS(type),.,NumSegBanks) +#define CURRENT_SEG_BANK(type) (NUM_SEG_BANKS(type) - 1) +// actual segment banks +#define SEG_BANKS_ARR(type) MEMBER(DYNARR_VARS(type),.,pSegBanksArr) diff --git a/dynarrc/dynarrc.vcxproj b/dynarrc/dynarrc.vcxproj index f1eac40..aa8e442 100644 --- a/dynarrc/dynarrc.vcxproj +++ b/dynarrc/dynarrc.vcxproj @@ -44,6 +44,10 @@ Level3 Disabled true + false + false + true + _MBCS;%(PreprocessorDefinitions);_CRT_SECURE_NO_WARNINGS ; true @@ -65,10 +69,20 @@ + + + + + + + + - + + + diff --git a/dynarrc/dynarrc.vcxproj.filters b/dynarrc/dynarrc.vcxproj.filters index 924c3f3..b70def6 100644 --- a/dynarrc/dynarrc.vcxproj.filters +++ b/dynarrc/dynarrc.vcxproj.filters @@ -21,9 +21,39 @@ Header Files + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + - + + Source Files + + + Source Files + + Source Files diff --git a/dynarrc/main.c b/dynarrc/main.c deleted file mode 100644 index 29e9dac..0000000 --- a/dynarrc/main.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "common.h" -#include -#include - -typedef struct MyStruct{ - int a; - float b; - char c; -}MyStruct; - -/*------ Allocator for MyStruct ------*/ -// fix the type for this allocator -#define DYNARR_DATA_TYPE MyStruct -#include "dynarr.h" -SEG_ARR_CREATE(MyStruct); -#undef DYNARR_DATA_TYPE - - -/*------ Allocator for MyStruct* ------*/ -typedef struct MyStruct* MyStructPtr; -#define DYNARR_DATA_TYPE MyStructPtr -#include "dynarr.h" -SEG_ARR_CREATE(MyStructPtr); -#undef DYNARR_DATA_TYPE - - - -int main(int argc, char** argv){ - MEM_LEAK_CATCH(); - // your code here - SEG_ARR_INIT(MyStruct); - DYNARR_SEG_TYPE(MyStruct) seg = NULL_SEG(MyStruct); - SEG_ARR_ALLOC_SEG(MyStruct, seg); - SEG_ARR_CLEANUP(MyStruct); - - SEG_ARR_INIT(MyStructPtr); - SEG_ARR_CLEANUP(MyStructPtr); - - // done - MEM_LEAK_SHOW(); - return 0; -} \ No newline at end of file diff --git a/dynarrc/test.c b/dynarrc/test.c new file mode 100644 index 0000000..aefd010 --- /dev/null +++ b/dynarrc/test.c @@ -0,0 +1,196 @@ +#include "common.h" +#include +#include +#include "CuTest.h" + +typedef struct MyStruct{ + int a; + float b; + char c; +}MyStruct; + +#define MAXSEG 16 +/*------ Allocator for MyStruct ------*/ +// fix the type for this allocator +#define DYNARR_DATA_TYPE MyStruct +#include "dynarr.h" +SEG_ARR_CREATE(MyStruct); // global allocator +#undef DYNARR_DATA_TYPE + + +/*------ Allocator for MyStruct* ------*/ +typedef struct MyStruct* MyStructPtr; +#define DYNARR_DATA_TYPE MyStructPtr +#include "dynarr.h" +#undef DYNARR_DATA_TYPE +SEG_ARR_CREATE(MyStructPtr); // global allocator + +// create, init, cleanup +void testCreateInitCleanup(CuTest* tc){ + int i; + + // init + SEG_ARR_INIT(MyStruct); + CuAssert(tc, "LogMaxSeg not 4", 4 == LOGMAXSEG(MyStruct)); + CuAssert(tc, "MaxSegRemainderBitMask not 15", 15 == MAXSEG_REMAINDER_BITMASK(MyStruct)); + CuAssert(tc, "insertPos not 1", 1 == SEG_INSERT_POS(MyStruct)); + CuAssert(tc, "TotalSegs not 0", 0 == TOTAL_SEGS(MyStruct)); + CuAssert(tc, "NULLSEG.index not 0", 0 == NULL_SEG(MyStruct).index); + CuAssert(tc, "NULLSEG not NULL", 1 == DYNARR_SEG_NULL(NULL_SEG(MyStruct))); + CuAssert(tc, "NULLSEG not NULL", 0 == DYNARR_SEG_NOT_NULL(NULL_SEG(MyStruct))); + CuAssert(tc, "SEGARR NULL", NULL != SEG_ARR(MyStruct)); + CuAssert(tc, "NUM_SEG_BANKS not 1", 1 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "MAX_SEG_BANKS not 1", 1 == MAX_SEG_BANKS(MyStruct)); + CuAssert(tc, "SEG_BANK_ALLOC_VIOLATION not 0", 0 == SEG_BANK_ALLOC_VIOLATION(MyStruct)); + CuAssert(tc, "SEG_BANKS_ARR NULL", NULL != SEG_BANKS_ARR(MyStruct)); + CuAssert(tc, "SEG_BANK_SIZE_ARR NULL", NULL != SEG_BANK_SIZE_ARR(MyStruct)); + CuAssert(tc, "SEG_BANK_INDEX_LIMIT_ARR NULL", NULL != SEG_BANK_INDEX_LIMIT_ARR(MyStruct)); + CuAssert(tc, "SEG_BANK_SIZE_ARR[0] not MAXSEG", MAXSEG == SEG_BANK_SIZE_ARR(MyStruct)[0]); + CuAssert(tc, "SEG_BANK_INDEX_LIMIT_ARR[0] not MAXSEG-1", (MAXSEG-1) == SEG_BANK_INDEX_LIMIT_ARR(MyStruct)[0]); + + // cleanup + SEG_ARR_CLEANUP(MyStruct); + CuAssert(tc, "SEGARR not NULL", NULL == SEG_ARR(MyStruct)); + for (i = 1; i < NUM_SEG_BANKS(MyStruct); i++){ + CuAssert(tc, "SEG_BANKS_ARR[i] not NULL", NULL == SEG_BANKS_ARR(MyStruct)[i]); + } + CuAssert(tc, "SEG_BANKS_ARR not NULL", NULL == SEG_BANKS_ARR(MyStruct)); + CuAssert(tc, "SEG_BANK_INDEX_LIMIT_ARR not NULL", NULL == SEG_BANK_INDEX_LIMIT_ARR(MyStruct)); + CuAssert(tc, "SEG_BANK_SIZE_ARR not NULL", NULL == SEG_BANK_SIZE_ARR(MyStruct)); + CuAssert(tc, "TotalSegs not 0", 0 == TOTAL_SEGS(MyStruct)); + CuAssert(tc, "NUM_SEG_BANKS not 0", 0 == NUM_SEG_BANKS(MyStruct)); +} + +// allocate segment +void testAllocSeg(CuTest* tc){ + int i; + DYNARR_SEG_TYPE(MyStruct) seg1, seg2, seg, tempSeg; + // init + SEG_ARR_INIT(MyStruct); + + /* Allocate one segment */ + seg1 = allocSeg(MyStruct); + CuAssert(tc, "first index not " TO_STRING(SEG_INSERT_POS_BEGIN), + SEG_INSERT_POS_BEGIN == seg1.index); + CuAssert(tc, "TotalSegs not 1", 1 == TOTAL_SEGS(MyStruct)); + CuAssert(tc, "NumSegBanks not 1", 1 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "free seg list not NULL", + NULL == FREESEG_LIST(MyStruct)); + CuAssert(tc, "free seg invalid-list not NULL", + NULL == FREESEG_INVALID_LIST(MyStruct)); + + // Allocate one more. this should go at index 2 + seg2 = allocSeg(MyStruct); + CuAssert(tc, "index not 2", 2 == seg2.index); + CuAssert(tc, "TotalSegs not 2", 2 == TOTAL_SEGS(MyStruct)); + + // now delete the first seg; it should go to the free list + freeSeg(MyStruct, seg1); + CuAssert(tc, "TotalSegs not 1", 1 == TOTAL_SEGS(MyStruct)); + CuAssert(tc, "deleted seg not in free list", + 1 == FREESEG_LIST(MyStruct)->index); + CuAssert(tc, "free seg invalid-list not NULL", + NULL == FREESEG_INVALID_LIST(MyStruct)); + + // Allocate one more. this should go at index 1 + // because that segment was previously deleted + // after this, the freeseg list should be empty + seg = allocSeg(MyStruct); + CuAssert(tc, "index not 1", 1 == seg.index); + CuAssert(tc, "TotalSegs not 2", 2 == TOTAL_SEGS(MyStruct)); + CuAssert(tc, "free seg list not NULL", + NULL == FREESEG_LIST(MyStruct)); + CuAssert(tc, "free seg invalid-list NULL", + NULL != FREESEG_INVALID_LIST(MyStruct)); + + // so far 3 slots are taken from first segment bank + // first one empty by design + // next two allocated + // Allocate more (MAXSEG-3) segments. Should still occupy only the first bank + // all allocations must succeed + for (i = 0; i < MAXSEG - 3; i++){ + tempSeg = allocSeg(MyStruct); + CuAssert(tc, "alloc failed", 0 == segNull(tempSeg)); + CuAssert(tc, "alloc violation", 0 == isAllocError(MyStruct)); + } + CuAssert(tc, "NumSegBanks not 1", 1 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "MaxSegBanks not 1", 1 == MAX_SEG_BANKS(MyStruct)); + // now allocate one more segment. This should cause segment bank allocation + CuAssert(tc, "SEG_INSERT_POS not indexLimit[0]+1", (SEG_BANK_INDEX_LIMIT_ARR(MyStruct)[0] + 1) == SEG_INSERT_POS(MyStruct)); + seg = allocSeg(MyStruct); + CuAssert(tc, "alloc failed", 0 == segNull(tempSeg)); + CuAssert(tc, "alloc violation", 0 == isAllocError(MyStruct)); + CuAssert(tc, "NumSegBanks not 2", 2 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "MaxSegBanks not 2", 2 == MAX_SEG_BANKS(MyStruct)); + CuAssert(tc, "index not indexLimit[0]+1", (SEG_BANK_INDEX_LIMIT_ARR(MyStruct)[0]+1) == seg.index); + + // Allocate more (MAXSEG-1) segments. Should still occupy only the first bank + // all allocations must succeed + for (i = 0; i < MAXSEG - 1; i++){ + tempSeg = allocSeg(MyStruct); + CuAssert(tc, "alloc failed", 0 == segNull(tempSeg)); + CuAssert(tc, "alloc violation", 0 == isAllocError(MyStruct)); + } + CuAssert(tc, "NumSegBanks not 2", 2 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "MaxSegBanks not 2", 2 == MAX_SEG_BANKS(MyStruct)); + CuAssert(tc, "SEG_INSERT_POS not indexLimit[1]+1", (SEG_BANK_INDEX_LIMIT_ARR(MyStruct)[1] + 1) == SEG_INSERT_POS(MyStruct)); + // now allocate one more segment. This should cause segment bank allocation + seg = allocSeg(MyStruct); + CuAssert(tc, "alloc failed", 0 == segNull(tempSeg)); + CuAssert(tc, "alloc violation", 0 == isAllocError(MyStruct)); + CuAssert(tc, "NumSegBanks not 3", 3 == NUM_SEG_BANKS(MyStruct)); + CuAssert(tc, "MaxSegBanks not 4", 4 == MAX_SEG_BANKS(MyStruct)); + CuAssert(tc, "index not indexLimit[1]+1", (SEG_BANK_INDEX_LIMIT_ARR(MyStruct)[1] + 1) == seg.index); + + // delete a particular segment, + // and see if next alloc gives that index + i = 5; + seg = getSegAt(MyStruct, i); + CuAssert(tc, "index not i", i == seg.index); + // delete it, then get one more segment + freeSeg(MyStruct, seg); + seg1 = allocSeg(MyStruct); + CuAssert(tc, "new index not deleted index", i == seg1.index); + + // cleanup + SEG_ARR_CLEANUP(MyStruct); + +} + +CuSuite* getBasicTestSuite(void) +{ + CuSuite* suite = CuSuiteNew(); + + SUITE_ADD_TEST(suite, testCreateInitCleanup); + SUITE_ADD_TEST(suite, testAllocSeg); + + return suite; +} + +void runAllTests(void) +{ + CuString *output = CuStringNew(); + CuSuite* suite = getBasicTestSuite(); + + //CuSuiteAddSuite(suite, auxSuite); + + CuSuiteRun(suite); + CuSuiteSummary(suite, output); + CuSuiteDetails(suite, output); + printf("%s\n", output->buffer); + + // + CuSuiteDelete(suite); + CuStringDelete(output); +} + +int main(int argc, char** argv){ + MEM_LEAK_CATCH(); + // your code here + runAllTests(); + // done + MEM_LEAK_SHOW(); + printf("\nPress any key..."); + getchar(); + return 0; +} \ No newline at end of file