Exemplo n.º 1
0
Arquivo: list.c Projeto: nperron/core
int ListDestroy(List **list)
{
    if (!list || !(*list))
    {
        return 0;
    }
    int shared = RefCountIsShared((*list)->ref_count);
    if (shared)
    {
        /*
         * We just detach from the list.
         */
        RefCountDetach((*list)->ref_count, (*list));
    }
    else
    {
        // We are the only ones using the list, we can delete it.
        ListNode *node = NULL;
        ListNode *p = NULL;
        for (node = (*list)->first; node; node = p)
        {
            if ((*list)->destroy)
                (*list)->destroy(node->payload);
            p = node->next;
            free(node);
        }
        RefCountDestroy(&(*list)->ref_count);
    }
    free((*list));
    *list = NULL;
    return 0;
}
Exemplo n.º 2
0
int BufferDestroy(Buffer **buffer)
{
    // If already NULL don't bother.
    if (!buffer || !*buffer)
    {
        return 0;
    }
    /*
     * Here is how it goes, if we are shared then we cannot destroy the buffer
     * we simply detach from it. If we are not shared we need to destroy the buffer
     * and the RefCount.
     */
    if (RefCountIsShared((*buffer)->ref_count))
    {
        RefCountDetach((*buffer)->ref_count, *buffer);
    }
    else
    {
        // We can destroy the buffer
        if ((*buffer)->buffer)
        {
            free ((*buffer)->buffer);
        }
        // Destroy the RefCount struct
        RefCountDestroy(&(*buffer)->ref_count);
    }
    free (*buffer);
    *buffer = NULL;
    return 0;
}
Exemplo n.º 3
0
int ListDestroy(List **list)
{
    if (!list || !(*list))
    {
        return 0;
    }
    int shared = RefCountIsShared((*list)->ref_count);
    if (!shared)
    {
        // We are the only ones using the list, we can delete it.
        ListNode *node = NULL;
        ListNode *p = NULL;
        for (node = (*list)->first; node; node = node->next)
        {
            if (p)
                free(p);
            if ((*list)->destroy)
                (*list)->destroy(node->payload);
            p = node;
        }
        if (p)
        {
            free(p);
        }
    }
    RefCountDetach((*list)->ref_count, (*list));
    free((*list));
    *list = NULL;
    return 0;
}
Exemplo n.º 4
0
/*
 * Helper method to detach lists.
 */
static void ListDetach(List *list)
{
    int shared = RefCountIsShared(list->ref_count);
    if (shared)
    {
        /*
         * 1. Perform a deep copy (expensive!)
         * 2. Detach
         */
        ListNode *p = NULL, *q = NULL, *newList = NULL;
        for (p = list->list; p; p = p->next)
        {
            if (newList)
            {
                q->next = (ListNode *)malloc(sizeof(ListNode));
                q->next->previous = q;
                q->next->next = NULL;
                q = q->next;
                if (p->payload)
                {
                    if (list->copy)
                    {
                        list->copy(p->payload, &q->payload);
                    }
                    else
                    {
                        q->payload = p->payload;
                    }
                }
            }
            else
            {
                // First element
                newList = (ListNode *)malloc(sizeof(ListNode));
                newList->next = NULL;
                newList->previous = NULL;
                if (p->payload)
                {
                    if (list->copy)
                    {
                        list->copy(p->payload, &newList->payload);
                    }
                    else
                    {
                        newList->payload = p->payload;
                    }
                }
                q = newList;
            }
        }
        list->list = newList;
        // Ok, we have our own copy of the list. Now we detach.
        RefCountDetach(list->ref_count, list);
        list->ref_count = NULL;
        RefCountNew(&list->ref_count);
        RefCountAttach(list->ref_count, list);
    }
}
Exemplo n.º 5
0
static void test_isSharedRefCount(void)
{
    int data1 = 0xdeadbeef;
    int data2 = 0xbad00bad;
    RefCount *refCount = NULL;

    // initialize the refcount
    RefCountNew(&refCount);
    assert_int_equal(0, refCount->user_count);
    assert_true(refCount->last == NULL);
    assert_true(refCount->users == NULL);

    // isShared should return false
    assert_false(RefCountIsShared(refCount));

    // attach it to the first data
    RefCountAttach(refCount, &data1);
    // Check the result
    assert_int_equal(1, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous == NULL);
    assert_true(refCount->last->user == (void *)&data1);

    // isShared should return false
    assert_false(RefCountIsShared(refCount));

    // Attach the second data
    RefCountAttach(refCount, &data2);
    // Check the result
    assert_int_equal(2, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous != NULL);
    assert_true(refCount->last->user == (void *)&data2);

    // isShared should return true
    assert_true(RefCountIsShared(refCount));

    // Detach and try again
    RefCountDetach(refCount, &data1);
    // Check the result
    assert_int_equal(1, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous == NULL);
    assert_true(refCount->last->user == (void *)&data2);

    // isShared should return false
    assert_false(RefCountIsShared(refCount));

    // Try isShared with a NULL refCount
    assert_false(RefCountIsShared(NULL));

    // Destroy the refcount
    RefCountDestroy(&refCount);
}
Exemplo n.º 6
0
void BufferZero(Buffer *buffer)
{
    /*
     * 1. Detach if shared, allocate a new buffer
     * 2. Mark used as zero.
     */
    if (!buffer)
    {
        return;
    }
    if (RefCountIsShared(buffer->ref_count))
    {
        RefCountDetach(buffer->ref_count, buffer);
        buffer->buffer = (char *)xmalloc(buffer->capacity);
        RefCountNew(&buffer->ref_count);
        RefCountAttach(buffer->ref_count, buffer);
    }
    buffer->used = 0;
}
Exemplo n.º 7
0
int BufferVPrintf(Buffer *buffer, const char *format, va_list ap)
{
    va_list aq;
    va_copy(aq, ap);
    if (!buffer || !format)
    {
        return -1;
    }
    int printed = 0;
    /*
     * We don't know how big of a buffer we will need. It might be that we have enough space
     * or it might be that we don't have enough space. Unfortunately, we cannot reiterate over
     * a va_list, so our only solution is to tell the caller to retry the call. We signal this
     * by returning zero. Before doing that we increase the buffer to a suitable size.
     * The tricky part is the implicit sharing and the reference counting, if we are not shared then
     * everything is easy, however if we are shared then we need a different strategy.
     */
    if (RefCountIsShared(buffer->ref_count))
    {
        char *new_buffer = NULL;
        new_buffer = (char *)xmalloc(buffer->capacity);
        RefCount *ref_count = buffer->ref_count;
        buffer->ref_count = NULL;
        RefCountNew(&buffer->ref_count);
        RefCountAttach(buffer->ref_count, buffer);
        RefCountDetach(ref_count, buffer);
        /*
         * Ok, now we need to take care of the buffer.
         */
        unsigned int i = 0;
        unsigned int used = 0;
        for (i = 0; i < buffer->used; ++i)
        {
            new_buffer[i] = buffer->buffer[i];
            if ((buffer->buffer[i] == '\0') && (buffer->mode == BUFFER_BEHAVIOR_CSTRING))
            {
                break;
            }
            ++used;
        }
        buffer->buffer = new_buffer;
        buffer->used = used;
    }
    printed = vsnprintf(buffer->buffer, buffer->capacity, format, aq);
    if (printed >= buffer->capacity)
    {
        /*
         * Allocate a larger buffer and retry.
         * We use the copy of the list.
         */
        if (printed > buffer->memory_cap)
        {
            /*
             * We would go over the memory_cap limit.
             */
            return -1;
        }
        unsigned int required_blocks = (printed / DEFAULT_BUFFER_SIZE) + 1;
        buffer->buffer = (char *)xrealloc(buffer->buffer, required_blocks * DEFAULT_BUFFER_SIZE);
        buffer->capacity = required_blocks * DEFAULT_BUFFER_SIZE;
        buffer->used = 0;
        printed = vsnprintf(buffer->buffer, buffer->capacity, format, ap);
        buffer->used = printed;
    }
    else
    {
        buffer->used = printed;
    }
    return printed;
}
Exemplo n.º 8
0
int BufferAppend(Buffer *buffer, const char *bytes, unsigned int length)
{
    if (!buffer || !bytes)
    {
        return -1;
    }
    if (length + buffer->used > buffer->memory_cap)
    {
        return -1;
    }
    if (RefCountIsShared(buffer->ref_count))
    {
        char *new_buffer = NULL;
        new_buffer = (char *)xmalloc(buffer->capacity);
        RefCount *ref_count = buffer->ref_count;
        buffer->ref_count = NULL;
        RefCountNew(&buffer->ref_count);
        RefCountAttach(buffer->ref_count, buffer);
        RefCountDetach(ref_count, buffer);
        /*
         * Ok, now we need to take care of the buffer.
         */
        unsigned int i = 0;
        unsigned int used = 0;
        for (i = 0; i < buffer->used; ++i)
        {
            new_buffer[i] = buffer->buffer[i];
            if ((buffer->buffer[i] == '\0') && (buffer->mode == BUFFER_BEHAVIOR_CSTRING))
            {
                break;
            }
            ++used;
        }
        buffer->buffer = new_buffer;
        buffer->used = used;
    }
    /*
     * Check if we have enough space, otherwise create a larger buffer
     */
    if (buffer->used + length >= buffer->capacity)
    {
        unsigned int required_blocks = ((buffer->used + length)/ DEFAULT_BUFFER_SIZE) + 1;
        buffer->buffer = (char *)xrealloc(buffer->buffer, required_blocks * DEFAULT_BUFFER_SIZE);
        buffer->capacity = required_blocks * DEFAULT_BUFFER_SIZE;
    }
    /*
     * We have a buffer that is large enough, copy the data.
     */
    unsigned int c = 0;
    unsigned int total = 0;
    for (c = 0; c < length; ++c)
    {
        buffer->buffer[c + buffer->used] = bytes[c];
        if ((bytes[c] == '\0') && (buffer->mode = BUFFER_BEHAVIOR_CSTRING))
        {
            break;
        }
        ++total;
    }
    buffer->used += total;
    if (buffer->mode == BUFFER_BEHAVIOR_CSTRING)
    {
        buffer->buffer[buffer->used] = '\0';
    }
    return buffer->used;
}
Exemplo n.º 9
0
static void test_attach_detach_RefCount(void)
{
    /*
     * This test does not check for NULL pointers, otherwise asserts will
     * be triggered. Neither does it check for non-existent owners.
     */
    int data1 = 0xdeadbeef;
    int data2 = 0xbad00bad;
    int data3 = 0x55aaaa55;
    RefCount *refCount = NULL;

    // initialize the refcount
    RefCountNew(&refCount);
    assert_int_equal(0, refCount->user_count);
    assert_true(refCount->last == NULL);
    assert_true(refCount->users == NULL);

    // attach it to the first data
    RefCountAttach(refCount, &data1);
    // Check the result
    assert_int_equal(1, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous == NULL);
    assert_true(refCount->last->user == (void *)&data1);

    // Attach the second data
    RefCountAttach(refCount, &data2);
    // Check the result
    assert_int_equal(2, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous != NULL);
    assert_true(refCount->last->user == (void *)&data2);

    // Detach the first data
    RefCountDetach(refCount, &data1);
    // Check the result
    assert_int_equal(1, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous == NULL);
    assert_true(refCount->last->user == (void *)&data2);

    // Attach the third data
    RefCountAttach(refCount, &data3);
    // Check the result
    assert_int_equal(2, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous != NULL);
    assert_true(refCount->last->user == (void *)&data3);

    // Attach the first data
    RefCountAttach(refCount, &data1);
    // Check the result
    assert_int_equal(3, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous != NULL);
    assert_true(refCount->last->user == (void *)&data1);

    // Detach the third data
    RefCountDetach(refCount, &data3);
    // Check the result
    assert_int_equal(2, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous != NULL);
    assert_true(refCount->last->user == (void *)&data1);

    // Detach the first data
    RefCountDetach(refCount, &data1);
    // Check the result
    assert_int_equal(1, refCount->user_count);
    assert_true(refCount->last->next == NULL);
    assert_true(refCount->last->previous == NULL);
    assert_true(refCount->last->user == (void *)&data2);

    /*
     * We cannot detach the last element because that will assert.
     * Whenever there is only one element the only thing is to destroy
     * the refcount.
     */

    // Destroy the refcount
    RefCountDestroy(&refCount);
}
Exemplo n.º 10
0
Arquivo: buffer.c Projeto: fkoner/core
int BufferPrintf(Buffer *buffer, const char *format, ...)
{
    /*
     * We declare two lists, in case we need to reiterate over the list because the buffer was
     * too small.
     */
    va_list ap;
    va_list aq;
    va_start(ap, format);
    va_copy(aq, ap);
    if (!buffer || !format)
    {
        va_end(aq);
        va_end(ap);
        return -1;
    }
    int printed = 0;
    /*
     * We don't know how big of a buffer we will need. It might be that we have enough space
     * or it might be that we don't have enough space. Unfortunately, we cannot reiterate over
     * a va_list, so our only solution is to tell the caller to retry the call. We signal this
     * by returning zero. Before doing that we increase the buffer to a suitable size.
     * The tricky part is the implicit sharing and the reference counting, if we are not shared then
     * everything is easy, however if we are shared then we need a different strategy.
     */
    if (RefCountIsShared(buffer->ref_count))
    {
        char *new_buffer = NULL;
        new_buffer = (char *)xmalloc(buffer->capacity);
        /*
         * Make a local copy of the variables that are required to restore to normality.
         */
        RefCount *ref_count = buffer->ref_count;
        /*
         * We try to attach first, since it is more likely that Attach might fail than
         * detach.
         */
        int result = 0;
        buffer->ref_count = NULL;
        RefCountNew(&buffer->ref_count);
        result = RefCountAttach(buffer->ref_count, buffer);
        if (result < 0)
        {
            /*
             * Restore and signal the error.
             */
            free (new_buffer);
            RefCountDestroy(&buffer->ref_count);
            buffer->ref_count = ref_count;
            va_end(aq);
            va_end(ap);
            return -1;
        }
        /*
         * Detach. This operation might fail, although it is very rare.
         */
        result = RefCountDetach(ref_count, buffer);
        if (result < 0)
        {
            /*
             * The ref_count structure has not been modified, therefore
             * we can reuse it.
             * We need to destroy the other ref_count though.
             */
            free (new_buffer);
            RefCountDestroy(&buffer->ref_count);
            buffer->ref_count = ref_count;
            va_end(aq);
            va_end(ap);
            return -1;
        }
        /*
         * Ok, now we need to take care of the buffer.
         */
        unsigned int i = 0;
        unsigned int used = 0;
        for (i = 0; i < buffer->used; ++i)
        {
            new_buffer[i] = buffer->buffer[i];
            if ((buffer->buffer[i] == '\0') && (buffer->mode == BUFFER_BEHAVIOR_CSTRING))
            {
                break;
            }
            ++used;
        }
        buffer->buffer = new_buffer;
        buffer->used = used;
    }
    printed = vsnprintf(buffer->buffer, buffer->capacity, format, aq);
    if (printed >= buffer->capacity)
    {
        /*
         * Allocate a larger buffer and retry.
         * Now is when having a copy of the list pays off :-)
         */
        if (printed > buffer->memory_cap)
        {
            /*
             * We would go over the memory_cap limit.
             */
            va_end(aq);
            va_end(ap);
            return -1;
        }
        unsigned int required_blocks = (printed / DEFAULT_BUFFER_SIZE) + 1;
        buffer->buffer = (char *)xrealloc(buffer->buffer, required_blocks * DEFAULT_BUFFER_SIZE);
        buffer->capacity = required_blocks * DEFAULT_BUFFER_SIZE;
        buffer->used = 0;
        printed = vsnprintf(buffer->buffer, buffer->capacity, format, ap);
        buffer->used = printed;
    }
    else
    {
        buffer->used = printed;
    }
    va_end(aq);
    va_end(ap);
    return printed;
}
Exemplo n.º 11
0
Arquivo: buffer.c Projeto: fkoner/core
int BufferAppend(Buffer *buffer, const char *bytes, unsigned int length)
{
    if (!buffer || !bytes)
    {
        return -1;
    }
    if (length + buffer->used > buffer->memory_cap)
    {
        return -1;
    }
    if (RefCountIsShared(buffer->ref_count))
    {
        char *new_buffer = NULL;
        new_buffer = (char *)xmalloc(buffer->capacity);
        /*
         * Make a local copy of the variables that are required to restore to normality.
         */
        RefCount *ref_count = buffer->ref_count;
        /*
         * We try to attach first, since it is more likely that Attach might fail than
         * detach.
         */
        int result = 0;
        buffer->ref_count = NULL;
        RefCountNew(&buffer->ref_count);
        result = RefCountAttach(buffer->ref_count, buffer);
        if (result < 0)
        {
            /*
             * Restore and signal the error.
             */
            free (new_buffer);
            RefCountDestroy(&buffer->ref_count);
            buffer->ref_count = ref_count;
            return -1;
        }
        /*
         * Detach. This operation might fail, although it is very rare.
         */
        result = RefCountDetach(ref_count, buffer);
        if (result < 0)
        {
            /*
             * The ref_count structure has not been modified, therefore
             * we can reuse it.
             * We need to destroy the other ref_count though.
             */
            free (new_buffer);
            RefCountDestroy(&buffer->ref_count);
            buffer->ref_count = ref_count;
            return -1;
        }
        /*
         * Ok, now we need to take care of the buffer.
         */
        unsigned int i = 0;
        unsigned int used = 0;
        for (i = 0; i < buffer->used; ++i)
        {
            new_buffer[i] = buffer->buffer[i];
            if ((buffer->buffer[i] == '\0') && (buffer->mode == BUFFER_BEHAVIOR_CSTRING))
            {
                break;
            }
            ++used;
        }
        buffer->buffer = new_buffer;
        buffer->used = used;
    }
    /*
     * Check if we have enough space, otherwise create a larger buffer
     */
    if (buffer->used + length >= buffer->capacity)
    {
        unsigned int required_blocks = ((buffer->used + length)/ DEFAULT_BUFFER_SIZE) + 1;
        buffer->buffer = (char *)xrealloc(buffer->buffer, required_blocks * DEFAULT_BUFFER_SIZE);
        buffer->capacity = required_blocks * DEFAULT_BUFFER_SIZE;
    }
    /*
     * We have a buffer that is large enough, copy the data.
     */
    unsigned int c = 0;
    unsigned int total = 0;
    for (c = 0; c < length; ++c)
    {
        buffer->buffer[c + buffer->used] = bytes[c];
        if ((bytes[c] == '\0') && (buffer->mode = BUFFER_BEHAVIOR_CSTRING))
        {
            break;
        }
        ++total;
    }
    buffer->used += total;
    if (buffer->mode == BUFFER_BEHAVIOR_CSTRING)
    {
        buffer->buffer[buffer->used] = '\0';
    }
    return buffer->used;
}