0

I am trying to come up with a generic buffer (or heap container - not sure how to call it) for generic objects. So I could have a large number of them in contiguous memory.

The header I did works, but I was wondering if you guys could help me understand what am I doing wrong if anything, or any gotchas/bugs I am missing here. Or any other re-factoring I could do to make it better.

buffer.h

#ifndef _ENGINE_BUFFER
#define _ENGINE_BUFFER

#include <cstdlib>
#include <cstdio>
#include <typeinfo>
#include <cstring>

// Defining buffer struct:
template <typename T>
struct Buffer {
    unsigned int _size;
    unsigned int _number_of_objects;
    unsigned int _head;
    unsigned int _next;
    unsigned int * _backlog;
    int _backlog_head;
    T* _buffer_address;
};

// Creating buffer:
template <typename T>
Buffer<T>* createBuffer(int size) {

    Buffer<T>* _buffer = (Buffer<Sprite>*) calloc(1, sizeof(Buffer<T>));

    if (_buffer) {
        *(_buffer) = Buffer<T>();

        _buffer->_size = size;
        _buffer->_number_of_objects = 0;
        _buffer->_head = 0;
        _buffer->_next = 0;
        _buffer->_backlog = (unsigned int*) calloc(size, sizeof(int));
        _buffer->_backlog_head = -1;
        _buffer->_buffer_address = (T*) calloc(size, sizeof(T));

        if(_buffer->_buffer_address) {
            return _buffer;
        }
    }

    return (Buffer<T>*) nullptr;
}

// Adding object to buffer:
template <typename T>
int addObjectToBuffer(Buffer<T>* _buffer, const T &_obj) {

    int _head = 0;

    if (_buffer->_backlog_head > -1) {
        _buffer->_buffer_address[_buffer->_backlog[_buffer->_backlog_head]] = _obj;

        _head = _buffer->_backlog_head;
        _buffer->_backlog_head--;
        _buffer->_number_of_objects++;

    } else {

        if ( (int) (_buffer->_number_of_objects + 1) >= _buffer->_size){

            T* _new_address = (T*) calloc((_buffer->_number_of_objects + 1) * 2, sizeof(T));
            memcpy(_new_address, _buffer->_buffer_address, _buffer->_number_of_objects * sizeof(T));
            free(_buffer->_buffer_address);

            _buffer->_buffer_address = _new_address;
            _buffer->_size = (_buffer->_number_of_objects + 1) * 2;

            for (int i = _buffer->_head; i < _buffer->_size; i++){
                _buffer->_buffer_address[i] = 0;
            }

        }

        _buffer->_buffer_address[_buffer->_head] = _obj;
        _buffer->_number_of_objects++;

        _head = _buffer->_head;
        _buffer->_head++;
    }

    return _head;
}

// Getting number of objects in buffer:
template <typename T>
unsigned int bufferGetSize(Buffer<T>* _buffer) {
    return (int) _buffer->_number_of_objects;
}

// Getting next object in buffer:
template <typename T>
T* bufferGetNext(Buffer<T>* _buffer) {

    if (_buffer->_backlog_head > -1){
        for (int i = 0; i <= _buffer->_backlog_head; i++ ) {
        if (_buffer->_backlog[i] == _buffer->_next) _buffer->_next++;;
    }
    }

    unsigned int _next = _buffer->_next;

    if (_next < _buffer->_head) {
        _buffer->_next++;

        return &_buffer->_buffer_address[_next];

    } else {
        _buffer->_next = 0;
        bufferGetNext(_buffer);
    }
}

// Reset iterator head:
template <typename T>
void bufferResetHead(Buffer<T>* _buffer){
    _buffer->_next = 0;
}

// Deleting object from buffer:
template <typename T>
void deleteObjectFromBuffer(Buffer<T>* _buffer, unsigned int _obj_index) {

    if (_obj_index >= 0 && _obj_index <= _buffer->_head) {

        bool _obj_exists = false;

        for (int i = _buffer->_backlog_head; i >= 0; i-- ) {
            if (_buffer->_backlog[i] == _obj_index){
                _obj_exists = true;
                fprintf(stderr, "\n[ Warning: object_deleted_twice | buffer: %#010x | object: %#010x | index: \"%d\" ]\n",
                _buffer, &_buffer->_buffer_address[_obj_index], _obj_index);
            }
        }

        if (!_obj_exists) {
            _buffer->_backlog_head++;
            _buffer->_backlog[_buffer->_backlog_head] = _obj_index;    
            _buffer->_number_of_objects--;
        }
    } else {
        fprintf(stderr, "\n[ Warning: index_out_of_range | buffer: %#010x | index: \"%d\" ]\n",
                _buffer, _obj_index);
    }
}

// Deleting buffer:
template <typename T>
void deleteBuffer(Buffer<T>* _buffer) {
    free(_buffer->_buffer_address);
    free(_buffer);
}

// Print buffer memory:
template <typename T>
void printBufferMemory(Buffer<T>* _buffer, unsigned int _number_of_columns, bool _print_address) {

    int _column_count = 0;

    printf("\n");
    printf("[ Number of objects in buffer: %#02d | Actual buffer size: %#02d ]\n", _buffer->_number_of_objects, _buffer->_size);

    for (int i = 1; i < 11 * _number_of_columns; i++) {
        printf("=");
    }

    printf("\n");

    for (int i = 0; i < _buffer->_size; i++) {

        if (_column_count > _number_of_columns - 1) {
            printf("\n"); 
            _column_count = 0;
        }

        if (_print_address) {
            printf("%#010x ", &_buffer->_buffer_address[i]);
        } else {
            printf("%#010d ", *(&_buffer->_buffer_address[i]));     
        }

        _column_count++;
    }
    printf("\n");

    for (int i = 1; i < 11 * _number_of_columns; i++) {
        printf("=");
    }

    printf("\n");
}

#endif // _ENGINE_BUFFER

sprite.h

#ifndef _SPRITE
#define _SPRITE

struct Sprite {
    int value = 0;

    Sprite(int n){
        value = n;
    }
};

#endif // _SPRITE

main.cpp

#include <cstdio>
#include <cstdlib>
#include "sprite.h"
#include "buffer.h"

using namespace std;

int main()
{

    int buffer_size = 512;
    int object_number = 512;

    Buffer<Sprite>* engine_buffer = createBuffer<Sprite>(buffer_size);

    for (int i = 0; i < object_number; i++) {
        addObjectToBuffer(engine_buffer, Sprite(i + 100));
    }

    for (int i = 0; i < bufferGetSize(engine_buffer); i++) {
        printf("Value of Sprite %d is: %d\n", i + 1, bufferGetNext(engine_buffer)->value);
    }

    printBufferMemory(engine_buffer, 10, false);
    deleteBuffer(engine_buffer);

    return(0);
}
Increasingly Idiotic
  • 5,700
  • 5
  • 35
  • 73
Leandro
  • 1
  • 1
  • 1
    Simple question -- what does your `Buffer` class do that [std::vector](http://en.cppreference.com/w/cpp/container/vector) is not able to do? – PaulMcKenzie Apr 23 '18 at 01:50
  • 1
    Unrelated to your question, but please read [What are the rules about using an underscore in a C++ identifier?](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier) – Some programmer dude Apr 23 '18 at 01:53
  • More related to your (to broad) question: Read about *unit testing*. And probably get [a few good books about C++](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) and learn to use it properly with classes and everything. – Some programmer dude Apr 23 '18 at 01:55
  • Your code introduces undefined behavior. The `Sprite` class is not a POD type, yet in `Buffer` you're creating memory for `Sprite` objects using `calloc`, then you're naively setting this memory to a `Sprite` object. That will not work -- this requires usage of `placement-new` if you plan on doing things that way. The `std::vector` class handles all of these details internally. If you want a simple, home-made vector class you can [start here](http://coliru.stacked-crooked.com/a/370b65fd41d93fc2) and just add the missing "remove element" function as an exercise. – PaulMcKenzie Apr 23 '18 at 02:04
  • @PaulMcKenzie Probably nothing, but my intent was just to try to do something like a vector myself. Studying purposes only. Thanks for pointing out the undefined behavior Paul. Will research on that. Cheers – Leandro Apr 23 '18 at 02:08
  • @Leandro See my comment -- I updated it to provide a link to a simple vector implementation. – PaulMcKenzie Apr 23 '18 at 02:08

0 Answers0