adds index type, refactors frame
authorThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Thu, 19 Sep 2024 13:47:02 +0000 (13:47 +0000)
committerThomas Walker Lynch <xtujpz@reasoningtechnology.com>
Thu, 19 Sep 2024 13:47:02 +0000 (13:47 +0000)
developer/cc/Frame.c
developer/cc/Index.c [new file with mode: 0644]
developer/cc/Pixel_2.c [deleted file]
developer/cc/Pixel_2024-09-18T2100.c [deleted file]
developer/cc/echo_frames_2024-09-18_1345.c [deleted file]
developer/cc/frame_2024-09-18_1221.c [deleted file]
developer/cc/test_size [new file with mode: 0755]
developer/cc/test_size.c [new file with mode: 0644]

index 91b18d5..106d0ac 100644 (file)
 /*
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
 };
diff --git a/developer/cc/Index.c b/developer/cc/Index.c
new file mode 100644 (file)
index 0000000..4d58c43
--- /dev/null
@@ -0,0 +1,281 @@
+/*
+   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;
+}
diff --git a/developer/cc/Pixel_2.c b/developer/cc/Pixel_2.c
deleted file mode 100644 (file)
index 400665d..0000000
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
-  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
-};
diff --git a/developer/cc/Pixel_2024-09-18T2100.c b/developer/cc/Pixel_2024-09-18T2100.c
deleted file mode 100644 (file)
index ce17e52..0000000
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-  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;
-}
diff --git a/developer/cc/echo_frames_2024-09-18_1345.c b/developer/cc/echo_frames_2024-09-18_1345.c
deleted file mode 100644 (file)
index dcea910..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-// 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;
-}
diff --git a/developer/cc/frame_2024-09-18_1221.c b/developer/cc/frame_2024-09-18_1221.c
deleted file mode 100644 (file)
index 829228a..0000000
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- 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);
-}
diff --git a/developer/cc/test_size b/developer/cc/test_size
new file mode 100755 (executable)
index 0000000..4e2e5b6
Binary files /dev/null and b/developer/cc/test_size differ
diff --git a/developer/cc/test_size.c b/developer/cc/test_size.c
new file mode 100644 (file)
index 0000000..1253513
--- /dev/null
@@ -0,0 +1,56 @@
+// 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;
+}