Code snippets:muldim sim

From C

Jump to: navigation, search

3 files. You might compile them together with something like:

 $ gcc -ansi -pedantic -o muldim_test muldim.c muldim_test.c

The first file is muldim_test.c:

/**** muldim_test.c - Shao Miller, April 4th, 2012 */

#include <stdlib.h>
#include <stdio.h>

#include "muldim.h"

/*** Macros */
#define CountOf(array) (sizeof (array) / sizeof *(array))

int main(void) {
    int result;
    muldim_t arr;
    muldim_t end;
    int test[2][3][4];
    int i, j, k, * ip;

    /* Assume failure */
    result = EXIT_FAILURE;

    /* Same dimensions as 'test' */
    arr = muldim_zalloc(sizeof (int), 3, 2, 3, 4);
    if (!arr.ptr) {
        goto err_arr;
      }

    muldim_dmp(arr);

    end = muldim_get(arr, 3, 1, 2, 4);
    if (!end.ptr) {
        goto err_end;
      }

    muldim_dmp(end);

    printf(
        "(\n"
        "    (char *) (test[1][2] + 4) -\n"
        "    (char *) test[0][0]\n"
        "  ) == %d\n",
        (
            (char *) (test[1][2] + 4) -
            (char *) test[0][0]
          )
      );

    printf(
        "(\n"
        "    (char *) end.ptr -\n"
        "    (char *) arr.ptr\n"
        "  ) == %d\n",
        (
            (char *) end.ptr -
            (char *) arr.ptr
          )
      );

    /* Same dimensions as 'test' */
    for (i = 0; i < CountOf(test); ++i) {
        for (j = 0; j < CountOf(test[0]); ++j) {
            ip = muldim_get(arr, 2, i, j).ptr;
            for (k = 0; k < CountOf(test[0][0]); ++k) {
                if (ip[k]) {
                    printf("muldim_zalloc failed!\n");
                    goto err_nonzero;
                  }
                ip[k] = 42;
                continue;
              }
            continue;
          }
        continue;
      }

    /* Success */
    printf("Yay\n");
    result = EXIT_SUCCESS;

    err_nonzero:

    err_end:

    free(arr.mem);
    err_arr:

    return result;
  }

The next file is the header muldim.h:

/**** muldim.h  - Shao Miller, April 4th, 2012 */

#ifndef MULDIM_H_

#include <stddef.h>

/*** Macros */
#define MULDIM_H_

/*** Object types */

typedef struct s_muldim s_muldim, muldim_t;

/*** Struct/union definitions */

struct s_muldim {
    void * ptr;
    size_t dims;
    size_t stride;
    size_t * dims_at;
    void * mem;
  };

/*** Function declarations */

extern muldim_t muldim_alloc(size_t base_sz, size_t dims, ...);
extern muldim_t muldim_zalloc(size_t base_sz, size_t dims, ...);
extern muldim_t muldim_get(muldim_t muldim, size_t dims, ...);
extern void muldim_dmp(muldim_t muldim);

#endif /* MULDIM_H_ */

And lastly we have muldim.c:

/**** muldim.c  - Shao Miller, April 4th, 2012 */

 #include <stddef.h>
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdio.h>

  #include "muldim.h"
 
/*** Function declarations */

static size_t sz_add(size_t x, size_t y);
static size_t sz_mul(size_t x, size_t y);

/*** Struct/union definitions */

struct s_muldim_wrapper {
    muldim_t muldim;
    size_t dims_hdr[1];
  };

/*** Object definitions */
static const muldim_t new_muldim;

/*** Function definitions */

muldim_t muldim_alloc(size_t base_sz, size_t dims, ...) {
    register const size_t dims_offset = offsetof(
        struct s_muldim_wrapper,
        dims_hdr
      );
    muldim_t result;
    size_t dims_sz;
    size_t hdr_sz;
    va_list vargs;
    size_t array_sz;
    size_t i;
    int dim;
    size_t total_sz;
    char * ptr;
    size_t * dims_at;

    result = new_muldim;

    if (!base_sz) {
        goto err_base_sz;
      }

    dims_sz = sz_mul(dims, sizeof result.dims_at[0]);
    if (!dims_sz) {
        goto err_dims_sz;
      }

    hdr_sz = sz_add(dims_offset, dims_sz);
    if (!hdr_sz) {
        goto err_hdr_sz;
      }
    hdr_sz = sz_add(base_sz, hdr_sz);
    if (!hdr_sz) {
        goto err_hdr_sz;
      }
    hdr_sz = hdr_sz - 1;
    hdr_sz = hdr_sz / base_sz;
    hdr_sz = hdr_sz * base_sz;

    va_start(vargs, dims);
    array_sz = base_sz;
    for (i = dims; i; --i) {
        dim = va_arg(vargs, int);
        if (dim < 1) {
            goto err_dim;
          }

        array_sz = sz_mul(array_sz, (size_t) dim);
        if (!array_sz) {
            goto err_array_sz;
          }

        continue;
      }
    va_end(vargs);

    total_sz = sz_add(hdr_sz, array_sz);
    if (!total_sz) {
        goto err_total_sz;
      }

    ptr = malloc(total_sz);
    if (!ptr) {
        goto err_ptr;
      }

    /* Success */

    dims_at = (void *) (ptr + dims_offset);

    va_start(vargs, dims);
    for (i = 0; i < dims; ++i) {
        dim = va_arg(vargs, int);
        dims_at[i] = (size_t) dim;

        continue;
      }
    va_end(vargs);

    result.ptr = ptr + hdr_sz;
    result.dims = dims;
    result.stride = array_sz;
    result.dims_at = dims_at;
    result.mem = ptr;

    *(muldim_t *) ptr = result;
    return result;

    free(ptr);
    err_ptr:

    err_total_sz:

    err_array_sz:

    err_dim:

    err_hdr_sz:

    err_dims_sz:

    err_base_sz:

    return result;
  }

muldim_t muldim_zalloc(size_t base_sz, size_t dims, ...) {
    register const size_t dims_offset = offsetof(
        struct s_muldim_wrapper,
        dims_hdr
      );
    muldim_t result;
    size_t dims_sz;
    size_t hdr_sz;
    va_list vargs;
    size_t array_sz;
    size_t i;
    int dim;
    size_t total_sz;
    char * ptr;
    size_t * dims_at;

    result = new_muldim;

    if (!base_sz) {
        goto err_base_sz;
      }

    dims_sz = sz_mul(dims, sizeof result.dims_at[0]);
    if (!dims_sz) {
        goto err_dims_sz;
      }

    hdr_sz = sz_add(dims_offset, dims_sz);
    if (!hdr_sz) {
        goto err_hdr_sz;
      }
    hdr_sz = sz_add(base_sz, hdr_sz);
    if (!hdr_sz) {
        goto err_hdr_sz;
      }
    hdr_sz = hdr_sz - 1;
    hdr_sz = hdr_sz / base_sz;
    hdr_sz = hdr_sz * base_sz;

    va_start(vargs, dims);
    array_sz = base_sz;
    for (i = dims; i; --i) {
        dim = va_arg(vargs, int);
        if (dim < 1) {
            goto err_dim;
          }

        array_sz = sz_mul(array_sz, (size_t) dim);
        if (!array_sz) {
            goto err_array_sz;
          }

        continue;
      }
    va_end(vargs);

    total_sz = sz_add(hdr_sz, array_sz);
    if (!total_sz) {
        goto err_total_sz;
      }

    total_sz = total_sz / base_sz;
    ptr = calloc(total_sz, base_sz);
    if (!ptr) {
        goto err_ptr;
      }

    /* Success */

    dims_at = (void *) (ptr + dims_offset);

    va_start(vargs, dims);
    for (i = 0; i < dims; ++i) {
        dim = va_arg(vargs, int);
        dims_at[i] = (size_t) dim;

        continue;
      }
    va_end(vargs);

    result.ptr = ptr + hdr_sz;
    result.dims = dims;
    result.stride = array_sz;
    result.dims_at = dims_at;
    result.mem = ptr;

    *(muldim_t *) ptr = result;
    return result;

    free(ptr);
    err_ptr:

    err_total_sz:

    err_array_sz:

    err_dim:

    err_hdr_sz:

    err_dims_sz:

    err_base_sz:

    return result;
  }

muldim_t muldim_get(muldim_t muldim, size_t dims, ...) {
    char * ptr;
    va_list vargs;
    int dim;

    if (!dims || dims > muldim.dims) {
        goto err_dims;
      }

    ptr = muldim.ptr;
    va_start(vargs, dims);
    while (dims--) {
        dim = va_arg(vargs, int);
        if (dim < 0 || dim > muldim.dims_at[0]) {
            goto err_dim;
          }

        muldim.stride = muldim.stride / muldim.dims_at[0];
        ptr = ptr + muldim.stride * dim;
        --muldim.dims;
        ++muldim.dims_at;

        continue;
      }
    va_end(vargs);

    /* Success */

    muldim.ptr = ptr;
    return muldim;

    err_dim:

    err_dims:

    return new_muldim;
  }

void muldim_dmp(muldim_t muldim) {
    printf(
        "ptr == %p\n"
        "dims == %u\n"
        "stride == %u\n"
        "dims_at == %p\n"
        "mem == %p\n",
        muldim.ptr,
        (unsigned int) muldim.dims,
        (unsigned int) muldim.stride,
        (void *) muldim.dims_at,
        muldim.mem
      );
    printf("dimensions: { ");
    while (muldim.dims--) {
        printf("%u, ", (unsigned int) muldim.dims_at++[0]);
        continue;
      }
    printf("}\n");
    return;
  }

static size_t sz_add(size_t x, size_t y) {
    size_t result;

    result = x + y;
    if (result <= x || result <= y) {
        /* Wrap-around */
        return 0;
      }
    return result;
  }

static size_t sz_mul(size_t x, size_t y) {
    size_t result;

    result = x * y;
    if (result <= x || result <= y) {
        /* Wrap-around */
        return 0;
      }
    return result;
  }
Personal tools