CODESAMPLE

Snapshot - C

Share on:

The Snapshot pattern captures and stores the internal state of an object at a specific point in time, allowing for restoration to that state later. This is useful for implementing undo/redo functionality, checkpoints, or transaction rollback. The C implementation uses a struct to hold the object’s state and functions to take and apply snapshots. It’s idiomatic C because it relies on explicit memory management and struct-based data representation, common practices in the language, avoiding complex object hierarchies or dynamic dispatch where unnecessary. The take_snapshot function copies the relevant data into a new snapshot struct, and restore_snapshot copies the data back from the snapshot to the original object.

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

// Original object
typedef struct {
  int value;
  char *data;
} MyObject;

// Snapshot struct
typedef struct {
  int value;
  char *data;
} MyObjectSnapshot;

// Function to create a new MyObject
MyObject *create_my_object(int initial_value, const char *initial_data) {
  MyObject *obj = (MyObject *)malloc(sizeof(MyObject));
  if (obj == NULL) {
    perror("Failed to allocate memory for MyObject");
    exit(EXIT_FAILURE);
  }
  obj->value = initial_value;
  obj->data = (char *)strdup(initial_data); // Duplicate the string
  if (obj->data == NULL) {
    perror("Failed to duplicate data string");
    free(obj);
    exit(EXIT_FAILURE);
  }
  return obj;
}

// Function to take a snapshot of the object
MyObjectSnapshot *take_snapshot(const MyObject *obj) {
  MyObjectSnapshot *snapshot = (MyObjectSnapshot *)malloc(sizeof(MyObjectSnapshot));
  if (snapshot == NULL) {
    perror("Failed to allocate memory for MyObjectSnapshot");
    exit(EXIT_FAILURE);
  }
  snapshot->value = obj->value;
  snapshot->data = (char *)strdup(obj->data); // Duplicate the string
  if (snapshot->data == NULL) {
    perror("Failed to duplicate data string");
    free(snapshot);
    exit(EXIT_FAILURE);
  }
  return snapshot;
}

// Function to restore the object from a snapshot
void restore_snapshot(MyObject *obj, const MyObjectSnapshot *snapshot) {
  obj->value = snapshot->value;
  free(obj->data); // Free existing data
  obj->data = (char *)strdup(snapshot->data); // Duplicate snapshot data
  if (obj->data == NULL) {
    perror("Failed to duplicate data string");
    exit(EXIT_FAILURE);
  }
}

// Function to free the object and its snapshot
void free_my_object(MyObject *obj) {
  free(obj->data);
  free(obj);
}

void free_my_object_snapshot(MyObjectSnapshot *snapshot) {
  free(snapshot->data);
  free(snapshot);
}

int main() {
  MyObject *obj = create_my_object(10, "Initial Data");
  printf("Original Object: value = %d, data = %s\n", obj->value, obj->data);

  MyObjectSnapshot *snapshot = take_snapshot(obj);

  obj->value = 20;
  obj->data = "Modified Data";
  printf("Modified Object: value = %d, data = %s\n", obj->value, obj->data);

  restore_snapshot(obj, snapshot);
  printf("Restored Object: value = %d, data = %s\n", obj->value, obj->data);

  free_my_object_snapshot(snapshot);
  free_my_object(obj);

  return 0;
}