// Please open settings (top right angle of the screent)
// and add the following compiler options:
// -Wall -std=gnu11 -Os -g -flto && objdump -S a.out
//
// then see objdump output in the bottom half of the screen
#include "circle.h"
#include "rectangle.h"
#include "line.h"
int main()
{
struct circle* circle = make_circle(1, 2, 3);
struct rectangle* rect = make_rectangle(4, 5, 6, 7);
struct line line = make_line(10, 11, 12, 13);
obj_draw(circle, 1);
obj_draw(rect, 2);
obj_draw(&line, 3);
obj_delete(circle);
obj_delete(rect);
obj_delete(&line);
return 0;
}
#include "graph.h"
// Declare Circle object and constructor function.
struct circle {
type_info(struct graph_objects, circle);
private_part;
};
struct circle* make_circle(int x, int y, unsigned r);
extern const struct object_vtable circle_vtable;
#pragma once
#include <stddef.h>
#include "util.h"
// base type tag for graphic object
typedef struct {} graph_base_t[0];
// virtual functions table for any object of single common class
struct object_vtable {
void (*draw)(graph_base_t *, int color);
void (*delete)(graph_base_t *);
};
typedef const struct object_vtable *object_vptr;
// structure carries type information for each of the object types
struct graph_objects {
object_vptr
circle,
rectangle,
line; // objects must be listed in advance... :-(
graph_base_t tag;
};
extern const struct graph_objects objects_info;
// implement functions from virtual functions table
#define obj_draw(obj, color) object_vptr(objects_info, obj)->draw(&(obj)->tag, color)
#define obj_delete(obj) object_vptr(objects_info, obj)->delete(&(obj)->tag)
#pragma once
#include <stddef.h>
// cast pointer to member to container struct
#define CONTAINER_OF(ptr, type, member) ((type*)((char*)(0 ? (0 ? NULL : &DECLVAL(type).member) : (ptr)) - offsetof(type, member)))
// Declare imaginary value of given type.
#define DECLVAL(type) (*(type *)0)
// declare "type_info" element carrying type information for objects
#define type_info(base, type) typeof(*DECLVAL(base).tag) tag[0]; char (*type_info[0])[offsetof(base, type)]
// declare private part of the object
#define private_part char _Alignas(_Alignof(max_align_t)) private[]
// get virtual functions table for the object
#define object_vptr(typeinfo, obj) (*(object_vptr*)&((const char*)&typeinfo)[sizeof(**(obj)->type_info)])
#include "graph.h"
// Declare Rectangle object and its constructor.
struct rectangle {
type_info(struct graph_objects, rectangle);
private_part;
};
struct rectangle* make_rectangle(int x1, int y1, int x2, int y2);
extern const struct object_vtable rectangle_vtable;
#include "graph.h"
// Same for a Line.
struct line {
int x1, y1, x2, y2; // public members
type_info(struct graph_objects, line);
};
static inline struct line make_line(int x1, int y1, int x2, int y2) { return (struct line){.x1=x1, .y1=y1, .x2=x2, .y2=y2}; }
extern const struct object_vtable line_vtable;
#include "graph.h"
#include "line.h"
#include "circle.h"
#include "rectangle.h"
const struct graph_objects objects_info = {
&circle_vtable,
&rectangle_vtable,
&line_vtable,
{}
};
#include <stdlib.h>
#include <stdio.h>
#include "circle.h"
///////// Circle implementation
struct circle_private {
int x, y;
unsigned r;
};
struct circle* make_circle(int x, int y, unsigned r)
{
struct circle *result = malloc(offsetof(struct circle, private[sizeof(struct circle_private)]));
if (!result) return NULL;
struct circle_private *this = (void*)result->private;
this->x = x, this->y = y, this->r = r;
return result;
}
void circle_draw(graph_base_t *tag, int color)
{
struct circle *circle = CONTAINER_OF(tag, struct circle, tag);
struct circle_private *this = (void*)circle->private;
printf("circle draw %d,%d r=%u with color %d\n", this->x, this->y, this->r, color);
}
void circle_delete(graph_base_t *tag)
{
struct circle *circle = CONTAINER_OF(tag, struct circle, tag);
struct circle_private *this = (void*)circle->private;
printf("circle delete %d,%d r=%u\n", this->x, this->y, this->r);
free(circle);
}
const struct object_vtable circle_vtable = { circle_draw, circle_delete };
#include <stdlib.h>
#include <stdio.h>
#include "rectangle.h"
//////// Rectangle implementation.
struct rectangle_private {
int x1, y1;
unsigned w, h;
};
struct rectangle* make_rectangle(int x1, int y1, int x2, int y2)
{
struct rectangle *result = malloc(offsetof(struct rectangle, private[sizeof(struct rectangle_private)]));
if (!result) return NULL;
struct rectangle_private *this = (void*)result->private;
this->x1 = x1, this->y1 = y1;
this->w = abs(x2 - x1), this->h = abs(y2 - y1);
return result;
}
void rectangle_draw(graph_base_t *tag, int color)
{
struct rectangle *rect = CONTAINER_OF(tag, struct rectangle, tag);
struct rectangle_private *this = (void*)rect->private;
printf("rectangle draw %d,%d -> %u,%u with color %d\n", this->x1, this->y1, this->w, this->h, color);
}
void rectangle_delete(graph_base_t *tag)
{
struct rectangle *rect = CONTAINER_OF(tag, struct rectangle, tag);
struct rectangle_private *this = (void*)rect->private;
printf("rectangle delete %d,%d -> %u,%u\n", this->x1, this->y1, this->w, this->h);
free(rect);
}
const struct object_vtable rectangle_vtable = { rectangle_draw, rectangle_delete };
#include <stdio.h>
#include <string.h>
#include "line.h"
/////// Line implementation.
void line_draw(graph_base_t *tag, int color)
{
struct line *this = CONTAINER_OF(tag, struct line, tag);
printf("line draw %d,%d -> %d,%d with color %d\n", this->x1, this->y1, this->x2, this->y2, color);
}
void line_delete(graph_base_t *tag)
{
struct line *this = CONTAINER_OF(tag, struct line, tag);
printf("line delete %d,%d -> %d,%d\n", this->x1, this->y1, this->x1, this->x2);
memset(this, 0, sizeof(struct line));
}
const struct object_vtable line_vtable = { line_draw, line_delete };