Make the reference count always odd to make it possible to distinguish it from a vtable
This commit is contained in:
parent
5df59c2f7e
commit
11c99d0b84
6 changed files with 59 additions and 45 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue