5
\$\begingroup\$

I have attempted doing a fluent API for creating random int arrays, and the following is what I came up with:

fluent_arrays.h:

#ifndef FLUENT_ARRAYS_H
#define FLUENT_ARRAYS_H

#define REQUEST_THREAD_LOCAL 1

#ifdef REQUEST_THREAD_LOCAL
#define THREAD_LOCAL __thread
#else
#define THREAD_LOCAL 
#endif

/*******************************************************************************
* The maximum integer selector.                                                *
*******************************************************************************/
typedef struct {
    int* (*with_maximum)(const int maximum);
} maximum_selector;

/*******************************************************************************
* The minimum integer selector.                                                *
*******************************************************************************/
typedef struct {
    maximum_selector* (*with_minimum)(const int minimum);
} minimum_selector;

/*******************************************************************************
* The array length selector.                                                   *
*******************************************************************************/
typedef struct {
    minimum_selector* (*of_length)(const size_t length);
} size_selector;

/*******************************************************************************
* Thread specific state.                                                       *
*******************************************************************************/
static THREAD_LOCAL int    tl_api_initialised = 0;
static THREAD_LOCAL int    tl_minimum;
static THREAD_LOCAL size_t tl_length;

/*******************************************************************************
* Global state.                                                                *
*******************************************************************************/
static size_selector       gl_size_selector;
static minimum_selector    gl_minimum_selector;
static maximum_selector    gl_maximum_selector;

/*******************************************************************************
* Implements maximum integer selection and creation of actual array.           *
*******************************************************************************/
static int* impl_with_maximum(const int maximum)
{
    int* p_array = malloc(tl_length);
    const int minimum = tl_minimum;

    for (size_t i = 0; i < tl_length; ++i) 
    {
        p_array[i] = (rand() % (maximum - minimum + 1)) + minimum;
    }

    return p_array;
}

/*******************************************************************************
* Implements minimum integer selection.                                        *
*******************************************************************************/
static maximum_selector* impl_with_minimum(const int minimum) 
{
    tl_minimum = minimum;
    return &gl_maximum_selector;
}

/*******************************************************************************
* Implements array length selection.                                           *
*******************************************************************************/
static minimum_selector* impl_with_length(const size_t length) 
{
    tl_length = length;
    return &gl_minimum_selector;
}

/*******************************************************************************
* Initiates the fluent API for creating random arrays.                         *
*******************************************************************************/
size_selector* create_random_array()
{
    if (!tl_api_initialised)
    {
        gl_size_selector.of_length = impl_with_length;
        gl_minimum_selector.with_minimum = impl_with_minimum;
        gl_maximum_selector.with_maximum = impl_with_maximum;

        tl_api_initialised = 1;
    }

    return &gl_size_selector;
}

#endif  /* FLUENT_ARRAYS_H */

main.c:

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

#include "fluent_arrays.h"

/*******************************************************************************
* Prints an integer array.                                                     *
*******************************************************************************/
static void print_int_array(const int *const p_array, const size_t length)
{
    for (size_t i = 0; i < length; ++i)
    {
        printf("%d ", p_array[i]);
    }

    puts("");
}

/*******************************************************************************
* The demonstration.                                                           *
*******************************************************************************/
int main(int argc, char** argv) {
    srand(time(NULL)); // <-- I know that this is not thread-safe.
    const size_t LENGTH = 30;

    // FUNKY FLUENT API IN C
    int* p_array = create_random_array()->of_length(LENGTH)
                                        ->with_minimum(-5)
                                        ->with_maximum(20);

    print_int_array(p_array, LENGTH);
    return (EXIT_SUCCESS);
}

My main question is: how can I make this thread-safe (*nix, Mac OS X, Windows)?

\$\endgroup\$
  • \$\begingroup\$ It seems that your code uses C99 at least, but do you also accept C11 answers? \$\endgroup\$ – Morwenn Apr 8 '15 at 15:05
  • \$\begingroup\$ @Morwenn Yes, everything goes. \$\endgroup\$ – coderodde Apr 8 '15 at 15:10
2
\$\begingroup\$

Range limits of integer math: rand() % (maximum - minimum + 1).

Should the user have minimum == 0 and maximum == RND_MAX ( a reasonable situation) which might be INT_MAX, then code is attempting undefined behavior with rand() % (INT_MAX + 1). Also it is easy enough for the width of the inclusive range [minimum ... maximum] to be greater than INT_MAX. A simple solution is to resort to a wider integer type. Example: int2x

// some wider type
int2x diff = (int2x) maximum - minimum + 1;
p_array[i] = rand() % diff + minimum;

Now diff could exceed the range of [0 ...RND_MAX]. In that case repeated calls to rand() (or other advanced schemes) are needed.

// Not highly efficient, but to show the point.
int2x r = (int2x) rand() * ((int2x) RND_MAX + 1) + rand();
p_array[i] = r % diff + minimum;

Using % can introduce random number generation bias. I'll assume OP is familiar with that. Many posts in SO discuss that like Generating random numbers in C

Minor: create_random_array() --> create_random_array(void) as the function should not accept any parameters.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.