//----------------------------------------------------------------------------- // Utility functions used by the Unix port. Notably, our memory allocation; // we use two separate allocators, one for long-lived stuff and one for // stuff that gets freed after every regeneration of the model, to save us // the trouble of freeing the latter explicitly. // // Copyright 2008-2013 Jonathan Westhues. // Copyright 2013 Daniel Richard G. //----------------------------------------------------------------------------- #include #include #ifdef __APPLE__ # include // for strcasecmp #endif #include "solvespace.h" namespace SolveSpace { void dbp(const char *str, ...) { va_list f; static char buf[1024*50]; va_start(f, str); vsnprintf(buf, sizeof(buf), str, f); va_end(f); fputs(buf, stderr); fputc('\n', stderr); } void assert_failure(const char *file, unsigned line, const char *function, const char *condition, const char *message) { fprintf(stderr, "File %s, line %u, function %s:\n", file, line, function); fprintf(stderr, "Assertion '%s' failed: ((%s) == false).\n", message, condition); #ifndef LIBRARY static void *ptrs[1024] = {}; size_t nptrs = backtrace(ptrs, sizeof(ptrs) / sizeof(ptrs[0])); char **syms = backtrace_symbols(ptrs, nptrs); fprintf(stderr, "Backtrace:\n"); if(syms != NULL) { for(size_t i = 0; i < nptrs; i++) { fprintf(stderr, "%2zu: %s\n", i, syms[i]); } } else { for(size_t i = 0; i < nptrs; i++) { fprintf(stderr, "%2zu: %p\n", i, ptrs[i]); } } #endif abort(); } bool PathEqual(const std::string &a, const std::string &b) { #if defined(__APPLE__) // Case-sensitivity is actually per-volume on OS X, // but it is tedious to implement and test for little benefit. return !strcasecmp(a.c_str(), b.c_str()); #else return a == b; #endif } FILE *ssfopen(const std::string &filename, const char *mode) { ssassert(filename.length() == strlen(filename.c_str()), "Unexpected null byte in middle of a path"); return fopen(filename.c_str(), mode); } void ssremove(const std::string &filename) { ssassert(filename.length() == strlen(filename.c_str()), "Unexpected null byte in middle of a path"); remove(filename.c_str()); } //----------------------------------------------------------------------------- // A separate heap, on which we allocate expressions. Maybe a bit faster, // since fragmentation is less of a concern, and it also makes it possible // to be sloppy with our memory management, and just free everything at once // at the end. //----------------------------------------------------------------------------- typedef struct _AllocTempHeader AllocTempHeader; typedef struct _AllocTempHeader { AllocTempHeader *prev; AllocTempHeader *next; } AllocTempHeader; static AllocTempHeader *Head = NULL; void *AllocTemporary(size_t n) { AllocTempHeader *h = (AllocTempHeader *)malloc(n + sizeof(AllocTempHeader)); h->prev = NULL; h->next = Head; if(Head) Head->prev = h; Head = h; memset(&h[1], 0, n); return (void *)&h[1]; } void FreeTemporary(void *p) { AllocTempHeader *h = (AllocTempHeader *)p - 1; if(h->prev) { h->prev->next = h->next; } else { Head = h->next; } if(h->next) h->next->prev = h->prev; free(h); } void FreeAllTemporary(void) { AllocTempHeader *h = Head; while(h) { AllocTempHeader *f = h; h = h->next; free(f); } Head = NULL; } void *MemAlloc(size_t n) { void *p = malloc(n); ssassert(p != NULL, "Cannot allocate memory"); return p; } void MemFree(void *p) { free(p); } void InitHeaps(void) { /* nothing to do */ } };