/*
- A display frame type.
+ The Frame type.
- Frames to be read or written are passed by reference.
-
- Functions that allocate a new frame typically return a reference to the
- newly allocated frame.
-
- Functions that accept an argument for holding an newly allocated frame, that
- argument will be a pointer to the frame reference. E.g. f(Frame **generated),
- *generated = NULL or *generated = malloc(...).
+ A size annotated 2D array of fixed sized elements.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <stdint.h>
-#include <stdbool.h>
//--------------------------------------------------------------------------------
-// Abstract Frame Interface for any pixel type
+// Frame instance
typedef struct {
- void (*alloc)(void *frame_instance, int width, int height);
- void (*alloc_external_data)(void *frame_instance, int width, int height, void *data);
- void (*dealloc)(void *frame_instance);
- void (*copy)(void *from_frame, void *to_frame);
- void (*read)(void *frame, int i, int j, void *result_px);
- void (*write)(void *frame, int i, int j, const void *px);
- void (*fill)(void *frame, const void *px);
- void (*every)(void *frame, void (*f)(void *frame, void *px, void *arg), void *arg);
-} Frame;
+ uint32_t pixel_size;
+ Index32·Instance data_array_bound; // array nx by ny
+ void *data;
+ void *meta_data; // whatever the programmer wants it to be
+} Frame·Instance;
-//--------------------------------------------------------------------------------
-// FrameGeneric instance state
+typedef void* (*PixelPredicate)(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg);
-typedef struct {
- uint32_t width;
- uint32_t height;
- Pixel *pixel_interface; // Pointer to the Pixel interface
- void *data; // Pointer to pixel data (generic)
- void *meta_data; // Optional metadata
-} FrameGeneric·Instance;
//--------------------------------------------------------------------------------
-// FrameGeneric interface
+// Frame interface implementation
+
+// Allocate a frame and its element data
+Frame·Instance *Frame·alloc(Index32·Instance data_array_bound ,uint32_t pixel_size ,void *metadata) {
+ // Check if either x or y is zero in the data_array_bound, which is not allowed
+ if( Index32·equal_or( Index32·structure(0, 0) ,data_array_bound) ){
+ fprintf(stderr ,"Frame·alloc:: zero x or zero y in data_array_bound not supported\n");
+ return NULL;
+ }
-// Allocate a frame and its pixel data
-void FrameGeneric·alloc(void *frame_instance, int width, int height) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- if (width == 0 || height == 0) {
- fprintf(stderr, "FrameGeneric·alloc:: invalid dimensions\n");
- return;
+ // Allocate memory for the frame instance
+ Frame·Instance *frame = malloc( sizeof(Frame·Instance) );
+ if( !frame ){
+ fprintf(stderr ,"Frame·alloc:: malloc() failed to allocate frame instance\n");
+ return NULL;
}
- frame->width = width;
- frame->height = height;
- size_t pixel_size = frame->pixel_interface->size();
- frame->data = malloc(width * height * pixel_size);
- if (!frame->data) {
- fprintf(stderr, "FrameGeneric·alloc:: failed to allocate pixel data\n");
+ // Set frame's data_array_bound and pixel_size
+ frame->data_array_bound = data_array_bound;
+ frame->pixel_size = pixel_size;
+
+ // Calculate total size for the data array and allocate it
+ size_t data_size;
+ if( !Index32·bounded_size(data_array_bound ,pixel_size ,&data_size) ){
+ fprintf(stderr ,"Frame·alloc:: bounded size too large for frame data array\n");
+ free(frame);
+ return NULL;
+ }
+
+ frame->data = malloc(data_size);
+ if( !frame->data ){
+ fprintf(stderr ,"Frame·alloc:: malloc() failed to allocate frame data array\n");
+ free(frame);
+ return NULL;
}
+
+ // Initialize metadata if provided
+ frame->meta_data = metadata;
+
+ return frame;
}
-// Allocate a frame with external pixel data
-void FrameGeneric·alloc_external_data(void *frame_instance, int width, int height, void *data) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- frame->width = width;
- frame->height = height;
- frame->data = data; // External data passed in
+// Allocate a frame with external element data
+void Frame·alloc_external_data(Frame·Instance *frame ,Index32·Instance data_array_bound ,uint32_t pixel_size ,void *external_data) {
+ // Check if either x or y in the data_array_bound is zero, which is not allowed
+ if( Index32·equal_or( Index32·structure(0, 0) ,data_array_bound) ){
+ fprintf(stderr ,"Frame·alloc_external_data:: zero x or zero y in data_array_bound not supported\n");
+ return;
+ }
+
+ // Set the frame's bounds and pixel size
+ frame->data_array_bound = data_array_bound;
+ frame->pixel_size = pixel_size;
+
+ // Assign the external data pointer to the frame
+ frame->data = external_data;
}
+
// Deallocate the frame
-void FrameGeneric·dealloc(void *frame_instance) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- if (frame->data) {
+void Frame·dealloc(Frame *frame_instance) {
+ Frame·Instance *frame = (Frame·Instance *)frame_instance;
+ if( frame->data ){
free(frame->data);
frame->data = NULL;
}
+ free(frame);
}
-// Copy one frame to another
-void FrameGeneric·copy(void *from_frame_instance, void *to_frame_instance) {
- FrameGeneric·Instance *from_frame = (FrameGeneric·Instance *)from_frame_instance;
- FrameGeneric·Instance *to_frame = (FrameGeneric·Instance *)to_frame_instance;
-
- if (to_frame->width != from_frame->width || to_frame->height != from_frame->height) {
- fprintf(stderr, "FrameGeneric·copy:: dimensions mismatch\n");
- return;
+-----
+// Access element at (i, j)
+void* Frame·access(Frame *frame_instance ,int i ,int j) {
+ Frame·Instance *frame = (Frame·Instance *)frame_instance;
+ if( i >= frame->width || j >= frame->height ){
+ fprintf(stderr ,"Frame·access:: index out of bounds\n");
+ return NULL;
}
-
- size_t pixel_size = from_frame->pixel_interface->size();
- memcpy(to_frame->data, from_frame->data, from_frame->width * from_frame->height * pixel_size);
+
+ return (char*)frame->data + (j * frame->width + i) * frame->element_size;
}
-// Read a pixel from the frame
-void FrameGeneric·read(void *frame_instance, int i, int j, void *result_px) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- if (i >= frame->width || j >= frame->height) {
- fprintf(stderr, "FrameGeneric·read:: index out of bounds\n");
- return;
+void* Frame·access(Frame·instance *frame ,Index32·Instance i){
+ size_t offset;
+ if( !Index32·linear_offset(i ,n ,frame->pixel_size ,offset) ){
+ return NULL;
}
-
- size_t pixel_size = frame->pixel_interface->size();
- void *px = (char *)frame->data + (j * frame->width + i) * pixel_size;
- memcpy(result_px, px, pixel_size);
+ return (char*)(frame->data) + offset;
}
-// Write a pixel to the frame
-void FrameGeneric·write(void *frame_instance, int i, int j, const void *px) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- if (i >= frame->width || j >= frame->height) {
- fprintf(stderr, "FrameGeneric·write:: index out of bounds\n");
- return;
- }
-
- size_t pixel_size = frame->pixel_interface->size();
- void *dst_px = (char *)frame->data + (j * frame->width + i) * pixel_size;
- memcpy(dst_px, px, pixel_size);
+bool Frame·read(Frame·instance *frame ,Index32·Instance i ,void *pixel){
+ void *pixel_in_frame = Frame·access(frame ,i);
+ if( !pixel_in_frame ) return false;
+ memcpy(pixel ,pixel_in_frame ,((Frame·Instance *)frame)->pixel_size);
+ return true;
}
-// Fill the frame with a specific pixel
-void FrameGeneric·fill(void *frame_instance, const void *px) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- for (int j = 0; j < frame->height; j++) {
- for (int i = 0; i < frame->width; i++) {
- FrameGeneric·write(frame_instance, i, j, px);
- }
- }
+bool Frame·write(Frame·Instance *frame ,Index32·Instance i ,const void *pixel){
+ void *pixel_in_frame = Frame·access(frame ,i);
+ if( !pixel_in_frame ) return false;
+ memcpy(pixel_in_frame ,pixel ,frame->pixel_size);
+ return true;
}
-// Apply a function to every pixel in the frame
-void FrameGeneric·every(void *frame_instance, void (*f)(void *frame, void *px, void *arg), void *arg) {
- FrameGeneric·Instance *frame = (FrameGeneric·Instance *)frame_instance;
- size_t pixel_size = frame->pixel_interface->size();
- for (int j = 0; j < frame->height; j++) {
- for (int i = 0; i < frame->width; i++) {
- void *px = (char *)frame->data + (j * frame->width + i) * pixel_size;
- f(frame_instance, px, arg);
+
+// Search for an element where f returns non-null (exist pattern)
+void* Frame·exist(Frame·Instance *frame ,Frame·PixelPredicate f ,void *arg) {
+ if (!frame || !f) return NULL;
+
+ Index32·Instance index = Index32·origin; // Start from (0, 0)
+ Index32·Instance bound = frame->data_array_bound;
+
+ do{
+ void *pixel = Frame·access(frame ,index);
+ if( pixel ){
+ void *result = f(frame ,pixel ,index ,arg);
+ if( result ) return result;
}
- }
+ }while( Index32·increment(&index ,bound ,frame->pixel_size) );
+
+ return NULL;
+}
+
+typedef struct {
+ Frame·PixelPredicate f; // PixelPredicate type for the function
+ void *arg; // User-provided metadata
+} Frame·every_arg_t;
+
+void *Frame·every_1(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg0) {
+ Frame·every_arg_t *ea = (Frame·every_arg_t *)arg0;
+ ea->f(frame ,pixel ,index ,ea->arg);
+ return NULL; // Return NULL for `every`
+}
+
+void Frame·every(Frame *frame ,Frame·PixelPredicate f ,void *arg) {
+ Frame·every_arg_t ea = {.f = f ,.arg = arg};
+ Frame·exist(frame ,Frame·every_1 ,&ea);
+}
+
+typedef struct {
+ Frame·PixelPredicate f; // PixelPredicate type for the function
+ void *arg; // User-provided metadata
+} Frame·all_arg_t;
+
+void *Frame·all_1(Frame *frame ,void *pixel ,Index32·Instance index ,void *arg0) {
+ Frame·all_arg_t *aa = (Frame·all_arg_t *)arg0;
+ if( !aa->f(frame ,pixel ,index ,aa->arg) ) return pixel; // If a pixel doesn't satisfy the predicate, return it
+ return NULL;
+}
+
+bool Frame·all(Frame *frame ,Frame·PixelPredicate f ,void *arg) {
+ Frame·all_arg_t aa = {.f = f ,.arg = arg};
+ return Frame·exist(frame ,Frame·all_1 ,&aa) == NULL; // If `exist` returns NULL, all elements satisfied the predicate
+}
+
+// Fill the frame with a specific pixel
+void *Frame·fill_1(Frame *frame ,void *pixel_in_frame ,Index32·Instance index ,void *arg) {
+ // `arg` contains the pixel value to fill with
+ const void *fill_pixel = arg;
+ memcpy(pixel_in_frame ,fill_pixel ,((Frame·Instance *)frame)->pixel_size);
+ return NULL; // Return NULL to indicate that we don't stop the loop (like `Frame·every`)
+}
+void Frame·fill(Frame *frame_instance ,const void *pixel) {
+ Frame·every(frame_instance ,Frame·fill_1 ,(void*)pixel);
}
//--------------------------------------------------------------------------------
-// FrameGeneric interface instance
-
-Frame FrameGeneric = {
- .alloc = FrameGeneric·alloc
- ,.alloc_external_data = FrameGeneric·alloc_external_data
- ,.dealloc = FrameGeneric·dealloc
- ,.copy = FrameGeneric·copy
- ,.read = FrameGeneric·read
- ,.write = FrameGeneric·write
- ,.fill = FrameGeneric·fill
- ,.every = FrameGeneric·every
+// Frame interface instance
+
+Frame Frame = {
+ .alloc = Frame·alloc
+ ,.alloc_external_data = Frame·alloc_external_data
+ ,.dealloc = Frame·dealloc
+ ,.copy = Frame·copy
+ ,.access = Frame·access
+ ,.read = Frame·read
+ ,.write = Frame·write
+ ,.exist = Frame·exist
+ ,.every = Frame·every
+ ,.all = Frame·all
+ ,.fill = Frame·fill
};
--- /dev/null
+/*
+ 32 bit 2D index, Used to index into the frame's data array.
+
+*/
+
+//--------------------------------------------------------------------------------
+// instance
+
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct {
+ uint32_t x;
+ uint32_t y;
+} Index32·Instance;
+
+Index32·Instance Index32·origin = {0 ,0};
+Index32·Instance Index32·unit_x = {1 ,0};
+Index32·Instance Index32·unit_y = {0 ,1};
+Index32·Instance Index32·unit = {1 ,1};
+Index32·Instance Index32·max = (UINT32_max ,UINT32_max);
+
+Index32·Instance Index32·structure(uint32_t x ,uint32_t y){
+ Index32·Instance i = {x ,y};
+ return i;
+}
+
+void Index32·destructure(Index32·Instance i ,uint32_t *x ,uint32_t *y){
+ *x = i.x;
+ *y = i.y;
+}
+
+void Index32·destructure_64(Index32·Instance i ,uint64_t *x ,uint64_t *y){
+ *x = i.x;
+ *y = i.y;
+}
+
+
+//--------------------------------------------------------------------------------
+// relative location predicates
+
+// i is left of n (x-coordinate comparison)
+bool Index32·i_left_of_n(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix < nx;
+}
+
+// i is right of n (x-coordinate comparison)
+bool Index32·i_right_of_n(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix > nx;
+}
+
+// i is above n (y-coordinate comparison)
+bool Index32·i_above_n(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return iy < ny;
+}
+
+// i is below n (y-coordinate comparison)
+bool Index32·i_below_n(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return iy > ny;
+}
+
+// i is at the same x-coordinate as n
+bool Index32·same_x(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix == nx;
+}
+
+// i is at the same y-coordinate as n
+bool Index32·same_y(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return iy == ny;
+}
+
+//--------------------------------------------------------------------------------
+// comparison prediates
+
+// Check if two Index32 instances are equal
+bool Index32·equal(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix == nx && iy == ny;
+}
+
+// Check if either coordinate (x or y) is equal
+bool Index32·equal_or(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix == nx || iy == ny;
+}
+
+// Check if both coordinates are less than the corresponding coordinates of n
+bool Index32·lesser(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix < nx && iy < ny;
+}
+
+// Check if either coordinate is less than the corresponding coordinate of n
+bool Index32·lesser_or(Index32·Instance i ,Index32·Instance n){
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ return ix < nx || iy < ny;
+}
+
+
+
+/* 1. If the length of x is not a multiple of delta, increment skips the last
+ (partial) element on a line.
+
+ 2. xn boundary first approach
+
+ xn is <= xmax, so if we pass xmax, we also pass xn (but not the converse).
+
+ for all x0, we derive the unknown x1:
+ x1 = x0 + delta
+
+ if x0 + delta > xmax there is an ov.
+ => if xmax - delta < x0 there is an ov, so: ov protected test:
+
+ beyond_xn = ((UNINT32_MAX - delta) < x0) || (x0 + delta > xn);
+
+ 3. xn boundary cleaner more intuitive approach (xn - x0 concept proposed by Saigen)
+
+ x0 + delta >= xn ; this test can overflow
+ delta >= xn - x0 ; we expect that x0 < xn, but both values were passed in.
+ ; we protect the subtract
+
+ beyond_xn = (x0 >= xn) || (delta >= xn - x0)
+
+ ^ first term is where the user passed in an x0 that is already off the
+ scan line. Second term is the ov safe x0 +delta >= xn test.
+
+ 4. yn boundary
+
+ y0 + 1 >= yn ; can overlow, note also y0 was passed in.
+
+*/
+bool Index32·increment(Index32·Instance *i ,Index32·Instance n ,uint32_t delta) {
+ uint32_t x0 ,y0 ,x1 ,y1 ,xn ,yn;
+ Index32·destructure(*i ,&x0 ,&y0);
+ Index32·destructure(n ,&xn ,&yn);
+
+ if(y0 >= yn) return false;
+ bool inc_beyond_xn= (x0 >= xn) || (delta > xn - x0);
+
+ if(inc_beyond_xn){
+ if(y0 + 1 >= yn) return false;
+ x1 = 0;
+ y1 = y0 + 1;
+ }else{
+ x1 = x0 + delta;
+ y1 = y0;
+ }
+
+ *i = Index32·structure(x1 ,y1);
+ return true;
+}
+
+/*
+ Sum two vectors. No clipping to the frame. Returns false if the computed
+ result would overflow the result representation.
+
+ ...
+
+ Suppose we were using UINT4 numbers, then UINT4_MAX would be 15. Now if a +
+ b > 15 there is an overlow, such a computation would have to be done in a
+ promoted sized arithmetic. However, note, 15 - a, in 4 bit arithmetic will
+ always be representable. Hence a + b > 15 ==> b > 15 - a, which can also be
+ stated as 15 - a < b.
+
+*/
+bool Index32·plus(Index32·Instance a ,Index32·Instance b ,Index32·Instance *c) {
+ uint32_t a_x ,a_y ,b_x ,b_y;
+
+ // Destructure a and b to get their x and y values
+ Index32·destructure(a ,&a_x ,&a_y);
+ Index32·destructure(b ,&b_x ,&b_y);
+
+ // Check for overflow
+ if( (UINT32_MAX - a_x) < b_x ) return false;
+ if( (UINT32_MAX - a_y) < b_y ) return false;
+
+ // Structure the result and assign to c
+ *c = Index32·structure(a_x + b_x ,a_y + b_y);
+
+ return true; // Successful addition without overflow
+}
+
+/*
+ Sum two vectors, returns false if the sum does not fit in the frame.
+
+ This function is overflow and underflow safe.
+*/
+bool Index32·plus_clipped(Index32·Instance base ,Index32·Instance delta ,Index32·Instance n ,Index32·Instance *result){
+ Index32·Instance sum;
+ if( !Index32·plus(base ,delta ,&sum) ) return false;
+ if( !Index32·lesser(sum ,n) ) return false;
+ *result = sum;
+ return true;
+}
+
+// Compute the number of bytes in 2D array with exclusive bound of n.
+bool Index32·bounded_size(Index32·Instance n ,uint32_t element_size ,size_t *result_area) {
+ uint64_t x = n.x;
+ uint64_t y = n.y;
+
+ // Count bits in x ,y, and element_size
+ int x_bits = count_bits(x);
+ int y_bits = count_bits(y);
+ int elem_bits = count_bits(element_size);
+
+ // Determine the nber of bits in SIZE_MAX
+ int max_bits = count_bits(SIZE_MAX);
+
+ // If the sum of the bits exceeds the number of bits in size_t, return false (overflow)
+ if (x_bits + y_bits + elem_bits > max_bits) {
+ return false; // Overflow detected
+ }
+
+ // Safe to calculate the area
+ *result_area = (size_t)x * (size_t)y * element_size;
+ return true; // Successful computation
+}
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+typedef struct {
+ uint32_t x;
+ uint32_t y;
+} Index32·Instance;
+
+// Calculates linear offset from the frame origin to index `i`, clipped to `n`
+bool Index32·linear_offset(Index32·Instance i ,Index32·Instance n ,uint32_t element_size ,size_t *offset) {
+ if( !Index32·lesser(i ,n) ) return false;
+
+ uint32_t ix ,iy ,nx ,ny;
+ Index32·destructure(i ,&ix ,&iy);
+ Index32·destructure(n ,&nx ,&ny);
+
+ *offset = (size_t)(iy * nx + ix) * element_size;
+
+ return true;
+}
+
+// Example destructure function (for reference)
+void Index32·destructure(Index32·Instance index ,uint32_t *x ,uint32_t *y) {
+ *x = index.x;
+ *y = index.y;
+}
+++ /dev/null
-/*
- Pixel types
-
- Currently implements only RGBA, which are specified by the hardware; hence
- they must be packed as: 0xAARRGGBB.
-
- For the sake of consistency, pixels are always passed by reference. Functions
- that generate new pixels return the new pixel by value.
-*/
-
-#include <endian.h>
-#include <stdint.h>
-#include <stdlib.h> // for rand()
-#include <stdbool.h>
-#include <time.h> // for seeding rand()
-
-//--------------------------------------------------------------------------------
-// Pixel Abstract Interface
-
-typedef struct {
- void* (*random)();
- void (*copy_from_uint32)(void *px0 ,uint32_t from_uint32);
- bool (*equal)(const void *px0 ,const void *px1);
- void* (*blend)(const void *px0 ,const void *px1);
- void* (*invert)(const void *px0);
- void* (*map_to_grayscale)(const void *px0);
- void* (*black)();
- void* (*white)();
- void* (*neutral)();
-} Pixel;
-
-//--------------------------------------------------------------------------------
-// instance state for RGBA pixel type
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- typedef union {
- uint32_t aggregate;
- struct __attribute__((packed)) {
- uint8_t blue;
- uint8_t green;
- uint8_t red;
- uint8_t alpha;
- };
- } PixelRGBA·Instance;
-#elif __BYTE_ORDER == __BIG_ENDIAN
- typedef union {
- uint32_t aggregate;
- struct __attribute__((packed)) {
- uint8_t alpha;
- uint8_t red;
- uint8_t green;
- uint8_t blue;
- };
- } PixelRGBA·Instance;
-#else
- #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors."
-#endif
-
-// Initialize a Pixel given the individual field values.
-void PixelRGBA·structure(PixelRGBA *px ,uint8_t red ,uint8_t green ,uint8_t blue ,uint8_t alpha){
- px->blue = blue;
- px->green = green;
- px->red = red;
- px->alpha = alpha;
-}
-
-// Decompose a Pixel into its individual color components.
-void PixelRGBA·destructure(PixelRGBA *px ,uint8_t *red ,uint8_t *green ,uint8_t *blue ,uint8_t *alpha){
- *blue = px->blue;
- *green = px->green;
- *red = px->red;
- *alpha = px->alpha;
-}
-
-//--------------------------------------------------------------------------------
-// interface for PixelRGBA type
-
-// Generate a black pixel.
-void* PixelRGBA·black(){
- PixelRGBA *px = malloc(sizeof(PixelRGBA));
- if( px ) px->aggregate = 0xff000000;
- return px;
-}
-
-// Generate a white pixel.
-void* PixelRGBA·white(){
- PixelRGBA *px = malloc(sizeof(PixelRGBA));
- if( px ) px->aggregate = 0xffffffff;
- return px;
-}
-
-// Generate a neutral pixel.
-void* PixelRGBA·neutral(){
- PixelRGBA *px = malloc(sizeof(PixelRGBA));
- if( px ) px->aggregate = 0x80808080;
- return px;
-}
-
-// Generate a random pixel.
-void* PixelRGBA·random(){
- PixelRGBA *px = malloc(sizeof(PixelRGBA));
- if( px == NULL ) return NULL;
-
- #if RAND_MAX < 0xFFFFFFFF
- px->aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
- #else
- px->aggregate = (uint32_t)rand();
- #endif
- return px;
-}
-
-// Copy from a uint32_t value to a PixelRGBA.
-void PixelRGBA·copy_from_uint32(void *instance ,uint32_t from_uint32){
- PixelRGBA *to_px = (PixelRGBA *)instance;
- to_px->aggregate = from_uint32;
-}
-
-// Check if two pixels are equal.
-bool PixelRGBA·equal(const void *px0 ,const void *px1){
- return ((PixelRGBA *)px0)->aggregate == ((PixelRGBA *)px1)->aggregate;
-}
-
-// Blend two pixels.
-void* PixelRGBA·blend(const void *px0 ,const void *px1){
- PixelRGBA *result = malloc(sizeof(PixelRGBA));
- if( !result ) return NULL;
-
- const PixelRGBA *p0 = (const PixelRGBA *)px0;
- const PixelRGBA *p1 = (const PixelRGBA *)px1;
-
- result->alpha = (p0->alpha + p1->alpha) / 2;
- result->red = (p0->red + p1->red) / 2;
- result->green = (p0->green + p1->green) / 2;
- result->blue = (p0->blue + p1->blue) / 2;
-
- return result;
-}
-
-// Invert the colors of a pixel.
-void* PixelRGBA·invert(const void *px0){
- PixelRGBA *result = malloc(sizeof(PixelRGBA));
- if( !result ) return NULL;
-
- const PixelRGBA *p = (const PixelRGBA *)px0;
- result->red = 255 - p->red;
- result->green = 255 - p->green;
- result->blue = 255 - p->blue;
- result->alpha = p->alpha; // Alpha remains unchanged
-
- return result;
-}
-
-// Convert a pixel to grayscale.
-void* PixelRGBA·map_to_grayscale(const void *px0){
- PixelRGBA *result = malloc(sizeof(PixelRGBA));
- if( !result ) return NULL;
-
- const PixelRGBA *p = (const PixelRGBA *)px0;
- uint8_t gray_level = (uint8_t)(0.299 * p->red + 0.587 * p->green + 0.114 * p->blue);
-
- result->red = gray_level;
- result->green = gray_level;
- result->blue = gray_level;
- result->alpha = p->alpha;
-
- return result;
-}
-
-//--------------------------------------------------------------------------------
-// PixelRGBA interface instance
-
-Pixel PixelRGBA·Interface = {
- .random = PixelRGBA·random
- ,.copy_from_uint32 = PixelRGBA·copy_from_uint32
- ,.equal = PixelRGBA·equal
- ,.blend = PixelRGBA·blend
- ,.invert = PixelRGBA·invert
- ,.map_to_grayscale = PixelRGBA·map_to_grayscale
- ,.black = PixelRGBA·black
- ,.white = PixelRGBA·white
- ,.neutral = PixelRGBA·neutral
-};
+++ /dev/null
-/*
- Pixel types
-
- Currently implements only RGBA, which are specified by the hardware; hence
- they must be packed as: 0xAARRGGBB.
-
- For the sake of consistency, pixels are always passed by reference. Functions
- that generate new pixels, return the new pixel by value.
-*/
-
-#include <endian.h>
-#include <stdint.h>
-#include <stdlib.h> // for rand()
-#include <time.h> // for seeding rand()
-
-//--------------------------------------------------------------------------------
-// instance state
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- typedef union{
- uint32_t aggregate;
- struct __attribute__((packed)) {
- uint8_t blue;
- uint8_t green;
- uint8_t red;
- uint8_t alpha;
- };
- } PixelRGBA;
-#elif __BYTE_ORDER == __BIG_ENDIAN
- typedef union{
- uint32_t aggregate;
- struct __attribute__((packed)) {
- uint8_t alpha;
- uint8_t red;
- uint8_t green;
- uint8_t blue;
- };
- } PixelRGBA;
-#else
- #warning "Pixel.c: unknown __BYTE_ORDER__ found when packing a PixelRGBA. Probably catastrophic, but compilation will continue so as to look for more errors."
-#endif
-
-// Initialize a Pixel given the individual field values.
-void PixelRGBA·structure
- (
- PixelRGBA *px
- ,uint8_t red
- ,uint8_t green
- ,uint8_t blue
- ,uint8_t alpha
- ){
- px->blue = blue;
- px->green = green;
- px->red = red;
- px->alpha = alpha;
-}
-
-// take apart a Pixel
-void PixelRGBA·destructure
- (
- PixelRGBA *px
- ,uint8_t *red
- ,uint8_t *green
- ,uint8_t *blue
- ,uint8_t *alpha
- ){
- *blue = px->blue;
- *green = px->green;
- *red = px->red;
- *alpha = px->alpha;
-}
-
-//--------------------------------------------------------------------------------
-// interface
-
-PixelRGBA PixelRGBA·black = {.aggregate = 0xff000000};
-PixelRGBA PixelRGBA·white = {.aggregate = 0xffffffff};
-PixelRGBA PixelRGBA·neutral = {.aggregate = 0x80808080};
-
-// makes a Pixel with a random value.
-PixelRGBA PixelRGBA·random(){
- PixelRGBA px;
- #if RAND_MAX < 0xFFFFFFFF
- px.aggregate = (((uint16_t)rand() & 0xFFFF) << 16) | ((uint16_t)rand() & 0xFFFF);
- #else
- px.aggregate = (uint32_t)rand();
- #endif
- #if RAND_MAX < 0xFFFF
- #warning "Pixel.c: warning standard rand() claims to deliver less than 16-bit values."
- #endif
- return px;
-}
-
-
-void PixelRGBA·copy_from_uint32(PixelRGBA *to_px ,uint32_t from_uint32){
- to_px->aggregate = from_uint32;
-}
-
-bool PixelRGBA·equals(const PixelRGBA *px0 ,const PixelRGBA *px1) {
- return px0->aggregate == px1->aggregate;
-}
-
-PixelRGBA PixelRGBA·blend(const PixelRGBA *px0 ,const PixelRGBA *px1) {
- PixelRGBA px2;
- px2.alpha = (px0->alpha + px1->alpha) / 2;
- px2.red = (px0->red + px1->red) / 2;
- px2.green = (px0->green + px1->green) / 2;
- px2.blue = (px0->blue + px1->blue) / 2;
- return px2;
-}
-
-PixelRGBA PixelRGBA·invert(const PixelRGBA *px0) {
- PixelRGBA px2;
- px2.red = 255 - px0->red;
- px2.green = 255 - px0->green;
- px2.blue = 255 - px0->blue;
- px2.alpha = px0->alpha;
- return px2;
-}
-
-PixelRGBA PixelRGBA·map_to_grayscale(const PixelRGBA *px0) {
- uint8_t gray_level = (uint8_t)(0.299 * px0->red + 0.587 * px0->green + 0.114 * px0->blue);
- PixelRGBA px1 =
- {
- .red = gray_level
- ,.green = gray_level
- ,.blue = gray_level
- ,.alpha = px0->alpha
- };
- return px1;
-}
+++ /dev/null
-// gcc -I/usr/include/libdrm echo_frames.c -o echo_frames -ldrm
-// sudo ./echo_frames
-
-/*
-Echos frames.
-
-Proof of principle: grabs frame, does nothing to it, then displays it, in a loop.
-*/
-
-#include <stdio.h> // For printf, fprintf, perror
-#include <stdlib.h> // For malloc, free, NULL
-#include <fcntl.h> // For open
-#include <unistd.h> // For close
-#include <string.h> // For memcpy
-#include <time.h> // For timing the loop
-#include <xf86drm.h> // For DRM functions
-#include <xf86drmMode.h> // For DRM Mode resources
-#include <sys/mman.h> // For mmap, munmap, PROT_READ, PROT_WRITE, MAP_SHARED, MAP_FAILED
-
-#include "Pixel.c"
-#include "Frame.c"
-
-int main() {
- int fd = open("/dev/dri/card2", O_RDWR | O_CLOEXEC); // Open the DRM device
- if(fd < 0){
- perror("Failed to open DRM device");
- return -1;
- }
-
- // Framebuffer ID: 108, resolution: 3840x2400
- int buffer_id = 108;
- int width = 3840;
- int height = 2400;
-
- // Allocate a DRM captured frame using the correct framebuffer ID
- FrameRGBA *drm_frame = FrameRGBA·alloc_capture_drm(fd, width, height, buffer_id);
- if(!drm_frame){
- fprintf(stderr, "Failed to allocate DRM frame\n");
- close(fd);
- return -1;
- }
-
- // Allocate a local frame for copying
- FrameRGBA *local_frame = FrameRGBA·alloc_local(1920, 1080);
- if(!local_frame){
- fprintf(stderr, "Failed to allocate local frame\n");
- FrameRGBA·dealloc(&drm_frame);
- close(fd);
- return -1;
- }
-
- // Get current time for the 5-second loop duration
- time_t start_time = time(NULL);
-
- // Loop for 5 seconds
- while(time(NULL) - start_time < 5){
- // Capture from the DRM frame and copy to the local frame
- FrameRGBA·copy(drm_frame, &local_frame);
-
- // Display the local frame (for simplicity, we use the DRM frame display method)
- if(FrameRGBA·display(local_frame, fd, 0, 0) < 0){ // Replace with proper crtc and connector IDs
- fprintf(stderr, "Failed to display local frame\n");
- FrameRGBA·dealloc(&drm_frame);
- FrameRGBA·dealloc(&local_frame);
- close(fd);
- return -1;
- }
- }
-
- // Clean up and close DRM device
- FrameRGBA·dealloc(&drm_frame);
- FrameRGBA·dealloc(&local_frame);
- close(fd);
-
- return 0;
-}
+++ /dev/null
-/*
- A display frame type.
-
- Frames to be read or written are passed by reference.
-
- Functions that allocate a new frame typically return a reference to the
- newly allocated frame.
-
- Functions that accept an argument for holding an newly allocated frame, that
- argument will be a pointer to the frame reference. E.g. f(Frame **generated),
- *generated = NULL or *gnerated = malloc(...).
-
-*/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-// --------------------------------------------------------------------------------
-// instance state
-
-typedef struct{
- uint32_t width;
- uint32_t height;
- PixelRGBA data[];
-} FrameRGBA;
-
-// --------------------------------------------------------------------------------
-// interface
-
-FrameRGBA *FrameRGBA·alloc(int width ,int height){
- bool null_frame = false;
-
- if( width == 0 ){
- fprintf(stderr ,"FrameRGBA·alloc:: frame width of zero, so returning a null frame pointer\n");
- null_frame = true;
- }
- if( height == 0 ){
- fprintf(stderr ,"FrameRGBA·alloc:: frame height of zero, so returning a null frame pointer\n");
- null_frame = true;
- }
- if(null_frame) return NULL;
-
- size_t size = sizeof(FrameRGBA) + width * height * sizeof(PixelRGBA);
- FrameRGBA *frame = malloc(size);
- if(!frame){
- fprintf(stderr ,"FrameRGBA·alloc::failed to allocate frame\n");
- return NULL;
- }
-
- frame->width = width;
- frame->height = height;
- return frame;
-}
-
-FrameRGBA *FrameRGBA·alloc_same(FrameRGBA *frame){
- if(!frame) return NULL;
- return FrameRGBA·alloc(frame->width ,frame->height);
-}
-
-void FrameRGBA·dealloc(FrameRGBA **frame){
- free(*frame);
- *frame = NULL;
-}
-
-void FrameRGBA·dimensions(FrameRGBA *frame ,uint32_t *width ,uint32_t *height){
- if(!frame){
- *width = 0;
- *height = 0;
- return;
- }
- *width = frame->width;
- *height = frame->height;
-}
-
-// both frames have already been allocated
-void FrameRGBA·copy(FrameRGBA *from_frame ,FrameRGBA **to_frame_arg){
- if( to_frame_arg == NULL ) return;
- if(*to_frame_arg == NULL) return;
- if( from_frame == NULL ){
- *to_frame_arg = NULL;
- return;
- }
- FrameRGBA *to_frame = *to_frame_arg;
-
- uint32_t width ,height;
- FrameRGBA·dimensions(from_frame ,&width ,&height);
- if(to_frame->width < width){
- width = to_frame->width;
- fprintf(stderr ,"FrameRGBA·copy:: from_frame is wider than to_frame, there will be truncation\n");
- }else if(to_frame->width > width){
- fprintf(stderr ,"FrameRGBA·copy:: to_frame is wider, so stale uninitialized pixels will remain at the end of scan lines.\n");
- }
- if(to_frame->height < height){
- height = to_frame->height;
- fprintf(stderr ,"FrameRGBA·copy:: from_frame is taller than to_frame, there will be truncation\n");
- }else if(to_frame->height > height){
- fprintf(stderr ,"FrameRGBA·copy:: to_frame is taller, so stale or uninitialized scan lines will remain at the bottom of the frame.\n");
- }
-
- uint32_t j = 0;
- uint32_t offset = 0;
- do{
- memcpy(
- to_frame->data + offset,
- from_frame->data + offset,
- width * sizeof(PixelRGBA)
- );
- offset += width;
- j++;
- }while(j < height);
-}
-
-// if i and j walk out of frame returns NULL
-PixelRGBA *FrameRGBA·access(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
- if(!from_frame) return NULL;
- uint32_t width ,height;
- FrameRGBA·dimensions(from_frame ,&width ,&height);
- if(i >= width) return NULL;
- if(j >= height) return NULL;
- return &(from_frame->data[j * width + i]);
-}
-
-PixelRGBA FrameRGBA·read(FrameRGBA *from_frame ,uint32_t i ,uint32_t j){
- if(!from_frame){
- fprintf(stderr, "FrameRGBA·read:: warning, empty frame, so returning a neutral pixel.");
- return PixelRGBA·neutral;
- }
- return *FrameRGBA·access(from_frame ,i ,j);
-}
-
-void FrameRGBA·write(FrameRGBA *to_frame ,uint32_t i ,uint32_t j ,PixelRGBA px){
- if(!to_frame){
- fprintf(stderr, "FrameRGBA·write:: warning, empty frame, write ignored.");
- return;
- }
- *FrameRGBA·access(to_frame ,i ,j) = px;
-}
-
-// search frame for condition where f returns a non-null pointer
-// f is handed successive pointers to pixels in the frame.
-// f is given the frame in case it needs context.
-// f is given an argument is it is difficult to curry functions in C.
-void *FrameRGBA·exist
-(
- FrameRGBA *frame
- ,void *(*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg)
- ,void *arg
- ){
-
- if(!frame) return NULL;
-
- void *item;
- uint32_t width ,height;
- FrameRGBA·dimensions(frame ,&width ,&height);
- uint32_t i = 0;
- uint32_t j = 0;
- do{
- PixelRGBA *px = FrameRGBA·access(frame ,i ,j);
- if( item=f(frame ,px ,arg) ) return item;
-
- if( i == width - 1 ){
- i = 0;
- j++;
- }else{
- i++;
- }
- }while(j < height);
- return NULL;
-}
-
-typedef struct{
- void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg);
- void *arg;
-} every_arg_t;
-void *every_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg0){
- every_arg_t *ea = arg0;
- ea->f(frame ,px ,ea->arg);
- return NULL;
-}
-void FrameRGBA·every
-(
- FrameRGBA *frame
- ,void (*f)(FrameRGBA *frame ,PixelRGBA *px ,void *arg)
- ,void *arg
- ){
- every_arg_t ea = {.f = f ,.arg = arg};
- FrameRGBA·exist(frame ,every_f ,&ea);
-}
-
-void fill_f(FrameRGBA *to_frame ,PixelRGBA *to_px ,void *arg){
- if(!to_frame) return;
- PixelRGBA *px = arg;
- *to_px = *px;
-}
-void FrameRGBA·fill(FrameRGBA *to_frame ,PixelRGBA *fill_px){
- if(!to_frame) return;
- FrameRGBA·every(to_frame ,fill_f ,fill_px);
-}
-
-void FrameRGBA·fill_black(FrameRGBA *to_frame){
- if(!to_frame) return;
- FrameRGBA·fill(to_frame ,&black);
-}
-
-void FrameRGBA·fill_white(FrameRGBA *to_frame){
- if(!to_frame) return;
- FrameRGBA·fill(to_frame ,&white);
-}
-
-void fill_random_f(FrameRGBA *frame ,PixelRGBA *px ,void *arg){
- *px = PixelRGBA·random();
-}
-void FrameRGBA·fill_random(FrameRGBA *frame){
- if(!frame) return;
- FrameRGBA·every(frame ,fill_random_f ,NULL);
-}
--- /dev/null
+// gcc test_size.c -o test_size
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <limits.h>
+
+#include "Index.c"
+
+// Helper function to count the nber of bits in a given nber
+int count_bits(uint64_t n) {
+ int bits = 0;
+ while (n) {
+ n >>= 1;
+ bits++;
+ }
+ return bits;
+}
+
+// Compute the number of bytes in 2D array with exclusive bound of n.
+bool Index32·bounded_size(Index32·Instance n, uint32_t element_size, size_t *result_area) {
+ uint64_t x = n.x;
+ uint64_t y = n.y;
+
+ // Count bits in x, y, and element_size
+ int x_bits = count_bits(x);
+ int y_bits = count_bits(y);
+ int elem_bits = count_bits(element_size);
+
+ // Determine the nber of bits in SIZE_MAX
+ int max_bits = count_bits(SIZE_MAX);
+
+ // If the sum of the bits exceeds the number of bits in size_t, return false (overflow)
+ if (x_bits + y_bits + elem_bits > max_bits) {
+ return false; // Overflow detected
+ }
+
+ // Safe to calculate the area
+ *result_area = (size_t)x * (size_t)y * element_size;
+ return true; // Successful computation
+}
+
+int main() {
+ Index32·Instance n = {50000, 50000}; // Example dimensions
+ uint32_t element_size = 16; // Example element size
+ size_t result_area;
+
+ bool success = Index32·bounded_size(n, element_size, &result_area);
+
+ if (!success) {
+ printf("Overflow detected during area calculation.\n");
+ } else {
+ printf("Area: %zu\n", result_area);
+ }
+ return 0;
+}