Beispiel #1
0
static void test_isEqualRefCount(void)
{
    int data2 = 0xbad00bad;
    RefCount *refCount1 = NULL;
    RefCount *refCount2 = NULL;

    // initialize refcount1
    RefCountNew(&refCount1);
    assert_int_equal(0, refCount1->user_count);
    assert_true(refCount1->last == NULL);
    assert_true(refCount1->users == NULL);

    // initialize refcount2 as a copy of refcount1
    refCount2 = refCount1;

    // isEqual should return true
    assert_true(RefCountIsEqual(refCount1, refCount2));

    /* Initialize refcount2 on its own */
    RefCountNew(&refCount2);
    assert_int_equal(0, refCount2->user_count);
    assert_true(refCount2->last == NULL);
    assert_true(refCount2->users == NULL);

    // isEqual should return false
    assert_false(RefCountIsEqual(refCount1, refCount2));

    // Add one to refcount1
    RefCountAttach(refCount1, &data2);

    // isEqual should return false
    assert_false(RefCountIsEqual(refCount1, refCount2));

    // Add the same to refcount2
    RefCountAttach(refCount2, &data2);

    // isEqual should return false
    assert_false(RefCountIsEqual(refCount1, refCount2));

    // Try one NULL
    assert_false(RefCountIsEqual(refCount1, NULL));
    assert_false(RefCountIsEqual(NULL, refCount2));

    // Both NULL
    assert_false(RefCountIsEqual(NULL, NULL));

    // Destroy both refcounts
    RefCountDestroy(&refCount1);
    RefCountDestroy(&refCount2);
}
Beispiel #2
0
// Simple initialization test
static void test_init_destroy_RefCount(void)
{
    RefCount *refCount = NULL;
    RefCountNew(&refCount);
    assert_int_equal(0, refCount->user_count);
    assert_true(refCount->last == NULL);
    assert_true(refCount->users == NULL);
    // Now we destroy the refcount.
    RefCountDestroy(&refCount);
    assert_true(refCount == NULL);

    // Try to destroy a NULL refCount
    RefCountDestroy(&refCount);
}
Beispiel #3
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;
}
Beispiel #4
0
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;
}
Beispiel #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);
}
Beispiel #6
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);
}
Beispiel #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);
        /*
         * 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;
    }
    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;
}
Beispiel #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);
        /*
         * 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;
}