diff --git a/inc/ManagedString.h b/inc/ManagedString.h index 5cf9c07..7ff9060 100644 --- a/inc/ManagedString.h +++ b/inc/ManagedString.h @@ -5,6 +5,7 @@ struct StringData : RefCounted { + uint16_t len; char data[0]; }; @@ -275,7 +276,7 @@ class ManagedString */ const char *toCharArray() const { - if (ptr->refcnt == 0) panic(243); + ptr->isReadOnly(); // this performs sanity checks on refCount return ptr->data; } @@ -293,7 +294,7 @@ class ManagedString */ int16_t length() const { - return ptr->size; + return ptr->len; } /** diff --git a/inc/MicroBitImage.h b/inc/MicroBitImage.h index 5fdbf3c..bb0e028 100644 --- a/inc/MicroBitImage.h +++ b/inc/MicroBitImage.h @@ -6,7 +6,9 @@ struct ImageData : RefCounted { - uint8_t data[0]; + uint8_t width; // Width in pixels + uint8_t height; // Height in pixels + uint8_t data[0]; // 2D array representing the bitmap image }; /** @@ -18,7 +20,6 @@ struct ImageData : RefCounted class MicroBitImage { ImageData *ptr; // Pointer to payload data - // Width/height (in pixels) are in high/low byte of ptr->size /** diff --git a/inc/RefCounted.h b/inc/RefCounted.h index 91eea8b..9d332ad 100644 --- a/inc/RefCounted.h +++ b/inc/RefCounted.h @@ -11,24 +11,12 @@ struct RefCounted { public: /** - * Number of outstanding references. Should never be zero (object should be deleted then). + * The high 15 bits hold the number of outstanding references. The lowest bit is always 1 + * to make sure it doesn't look like vtable. + * Should never be even or one (object should be deleted then). * When it's set to 0xffff, it means the object sits in flash and should not be counted. */ - uint16_t refcnt; - - /** - * For strings this is length. For images this is both width and length (8 bit each). - * A value of 0xffff indicates that this is in fact an instance of VirtualRefCounted - * and therefore when the reference count reaches zero, the virtual destructor - * should be called. - */ - union { - uint16_t size; - struct { - uint8_t width; - uint8_t height; - }; - }; + uint16_t refCount; /** Increment reference count. */ void incr(); @@ -36,6 +24,11 @@ public: /** Decrement reference count. */ void decr(); + /** Initializes for one outstanding reference. */ + void init(); + + /** Checks if the object sits in flash memory. */ + bool isReadOnly(); }; #endif diff --git a/source/ManagedString.cpp b/source/ManagedString.cpp index 5d79f95..c730967 100644 --- a/source/ManagedString.cpp +++ b/source/ManagedString.cpp @@ -26,8 +26,8 @@ void ManagedString::initString(const char *str) // We assume the string is sane, and null terminated. int len = strlen(str); ptr = (StringData *) malloc(4+len+1); - ptr->size = len; - ptr->refcnt = 1; + ptr->init(); + ptr->len = len; memcpy(ptr->data, str, len+1); } @@ -96,8 +96,8 @@ ManagedString::ManagedString(const ManagedString &s1, const ManagedString &s2) // Create a new buffer for holding the new string data. ptr = (StringData*) malloc(4+len+1); - ptr->size = len; - ptr->refcnt = 1; + ptr->init(); + ptr->len = len; // Enter the data, and terminate the string. memcpy(ptr->data, s1.toCharArray(), s1.length()); @@ -132,9 +132,9 @@ ManagedString::ManagedString(const char *str, const int16_t length) // Allocate a new buffer, and create a NULL terminated string. ptr = (StringData*) malloc(4+length+1); + ptr->init(); // Store the length of the new string - ptr->size = length; - ptr->refcnt = 1; + ptr->len = length; memcpy(ptr->data, str, length); ptr->data[length] = 0; } @@ -331,8 +331,6 @@ ManagedString ManagedString::substring(int16_t start, int16_t length) */ ManagedString ManagedString::operator+ (ManagedString& s) { - //printf("add(%d,%d)\n", this->length(), s.length()); uBit.sleep(100); - // If the other string is empty, nothing to do! if(s.length() == 0) return *this; diff --git a/source/MicroBitImage.cpp b/source/MicroBitImage.cpp index ed4d97a..a5c7781 100644 --- a/source/MicroBitImage.cpp +++ b/source/MicroBitImage.cpp @@ -218,9 +218,9 @@ void MicroBitImage::init(const int16_t x, const int16_t y, const uint8_t *bitmap // Create a copy of the array ptr = (ImageData*)malloc(4 + x * y); + ptr->init(); ptr->width = x; ptr->height = y; - ptr->refcnt = 1; // create a linear buffer to represent the image. We could use a jagged/2D array here, but experimentation // showed this had a negative effect on memory management (heap fragmentation etc). @@ -283,7 +283,7 @@ bool MicroBitImage::operator== (const MicroBitImage& i) if (ptr == i.ptr) return true; else - return (ptr->size == i.ptr->size && (memcmp(getBitmap(), i.ptr->data, getSize())==0)); + return (ptr->width == i.ptr->width && ptr->height == i.ptr->height && (memcmp(getBitmap(), i.ptr->data, getSize())==0)); } diff --git a/source/RefCounted.cpp b/source/RefCounted.cpp index 123f73a..b8d646e 100644 --- a/source/RefCounted.cpp +++ b/source/RefCounted.cpp @@ -1,27 +1,48 @@ #include "mbed.h" #include "MicroBit.h" +void RefCounted::init() +{ + // Initialize to one reference (lowest bit set to 1) + refCount = 3; +} + +static inline bool isReadOnlyInline(RefCounted *t) +{ + uint32_t refCount = t->refCount; + + if (refCount == 0xffff) + return true; // object in flash + + // Do some sanity checking while we're here + if (refCount == 1) + uBit.panic(30); // object should have been deleted + + if ((refCount & 1) == 0) + uBit.panic(31); // refCount doesn't look right + + // Not read only + return false; +} + +bool RefCounted::isReadOnly() +{ + return isReadOnlyInline(this); +} + void RefCounted::incr() { - if (refcnt == 0xffff) - return; - if (refcnt == 0) - uBit.panic(30); - refcnt++; + if (!isReadOnlyInline(this)) + refCount += 2; } void RefCounted::decr() { - if (refcnt == 0xffff) + if (isReadOnlyInline(this)) return; - if (refcnt == 0) - uBit.panic(31); - refcnt--; - if (refcnt == 0) { - // size of 0xffff indicates a class with a virtual destructor - if (size == 0xffff) - uBit.panic(32); - else - free(this); + + refCount -= 2; + if (refCount == 2) { + free(this); } }