Thread overview
Manually allocated structs
Jul 27, 2014
Adam D. Ruppe
July 27, 2014
Hello !

I have the code bellow that I want to manually allocate to use in runtime code, because I declared the payload "buf[1]" the compiler complains about index out of bounds then I managed to do this "*(&tmp.buf + tmp.used++) = c;" instead of "tmp.buf[tmp.used++] = c;" as is done usually i "C" there is another easy way to achieve the same result in "D" (remember manual memory allocation) ?

Cheers !

--------Code

struct lua_char_buffer_st {
    size_t size, used;
    char buf[1];
};

private enum MIN_ALLOC_SIZE = 2048;
private size_t NEW_SIZE(size_t sz) {return (((sz/MIN_ALLOC_SIZE)+1)*MIN_ALLOC_SIZE);}

lua_char_buffer_st *lua_new_char_buffer(size_t size){
	lua_char_buffer_st *b;
	size_t n = NEW_SIZE(size);
	b = cast(lua_char_buffer_st*)malloc(lua_char_buffer_st.sizeof + n);
	if(b is null) return null;
	b.size = n;
	b.used = 0;
	return b;
}

int lua_char_buffer_add_char(ref LuaMatchState ms, lua_char_buffer_st **b, char c){
    lua_char_buffer_st *tmp = *b;
    if(tmp.used+1 >= tmp.size){
        size_t new_size = tmp.size+MIN_ALLOC_SIZE;
        tmp = cast(lua_char_buffer_st*)realloc(tmp, lua_char_buffer_st.sizeof + new_size);
        if(tmp is null){
            ms.error = "not enough memory when reallocating";
            return 0;
        }
        *b = tmp;
        tmp.size = new_size;
    }
    *(&tmp.buf + tmp.used++) = c;
    return 1;
}


int lua_char_buffer_add_str(ref LuaMatchState ms, lua_char_buffer_st **b, const(char) *str, ptrdiff_t len){
    lua_char_buffer_st *tmp = *b;
    if(len < 0) len = strlen(str);
    if(tmp.used+len >= tmp.size){
        size_t new_size = tmp.size + NEW_SIZE(len);
        tmp = cast(lua_char_buffer_st*)realloc(tmp, lua_char_buffer_st.sizeof + new_size);
        if(tmp is null){
            ms.error = "not enough memory when reallocating";
            return 0;
        }
        *b = tmp;
        tmp.size = new_size;
    }
    memcpy(&tmp.buf + tmp.used, str, len);
    tmp.used += len;
    return 1;
}
July 27, 2014
I would do it something like this:

struct test {
	size_t size;

	@property char[] buf() {
		return (_buf.ptr)[0 .. size];
	}
	private char[0] _buf;
}


The buf property returns a slice that uses the size member to give you bounds checking, but uses the ptr of the final member in the struct to bypass bounds checking on that array.

That way, you can allocate as much memory as you need without having to use the naked pointer anywhere outside, getting D to help you stay in bounds.
July 27, 2014
On Sunday, 27 July 2014 at 12:49:01 UTC, Adam D. Ruppe wrote:
> I would do it something like this:
>
> struct test {
> 	size_t size;
>
> 	@property char[] buf() {
> 		return (_buf.ptr)[0 .. size];
> 	}
> 	private char[0] _buf;
> }
>
>
> The buf property returns a slice that uses the size member to give you bounds checking, but uses the ptr of the final member in the struct to bypass bounds checking on that array.
>
> That way, you can allocate as much memory as you need without having to use the naked pointer anywhere outside, getting D to help you stay in bounds.

Yes it did what I was expecting, thank you !

July 27, 2014
Hello again !

Anyone knows how to compile with gdc for different versions I could not find how gdc implements it if it does ?

The proposed usage of "@property char[] buf()" although seems to work when compiled with dmd, segfaults when compiled with gdc:

----Code to test

import std.stdio;
import core.stdc.stdlib;

//version(c_style) {
	struct lua_char_buffer_st0 {
	    size_t size, used;
		char[1] buf;
	};
//}

//version(d_style) {
	struct lua_char_buffer_st2 {
	    size_t size, used;
		@property char[] buf() {
			return (_buf.ptr)[0 .. size];
		}
		private char[0] _buf;
	};
//}

//alias lua_char_buffer_st = lua_char_buffer_st0;
alias lua_char_buffer_st = lua_char_buffer_st2;
	
private enum MIN_ALLOC_SIZE = 2048;
private size_t NEW_SIZE(size_t sz) {return (((sz/MIN_ALLOC_SIZE)+1)*MIN_ALLOC_SIZE);}

lua_char_buffer_st *lua_realloc_char_buffer(lua_char_buffer_st *old, size_t size){
	lua_char_buffer_st *b = old;
	size_t n = NEW_SIZE(size);
	b = cast(lua_char_buffer_st*)realloc(old, lua_char_buffer_st.sizeof + n);
	if(b is null) return null;
	b.size = n;
	if(old is null) b.used = 0;
	return b;
}

int lua_char_buffer_add_char(lua_char_buffer_st **b, char c){
    lua_char_buffer_st *tmp = *b;
    if(tmp.used+1 >= tmp.size){
        tmp = lua_realloc_char_buffer(tmp, tmp.used+1);
        if(tmp is null){
            return 0;
        }
        *b = tmp;
    }
    //printf("lua_char_buffer_add_char %p : %p : %d : %d", &tmp.buf, tmp.buf.ptr, tmp.size, tmp.used);
    //fflush(stdout);
    //version(c_style)
    //*(&tmp.buf + tmp.used++) = c;
    //version(d_style)
    tmp.buf[tmp.used++] = c;
    return 1;
}

void main()
{
	lua_char_buffer_st *b = lua_realloc_char_buffer(null, MIN_ALLOC_SIZE);
	lua_char_buffer_add_char(&b, 'a');
	free(b);
	writeln("Hello !");
}