design_patterns - RicoJia/notes GitHub Wiki

Simple Design Patterns

Iterative Macros

  • Motivation: when you iterate over a linked list
     current = current->head; 
     while (current){
     	// DO STUFF
     	current = current -> next; 
     }
    This is error prone, and not safe.
  • For loop semantics:
    • The ++i part gets executed last
  • Form
     #define ITERATE_LIST_BEGIN(list_ptr, node_ptr)                              \
     {                                                                           \
     	dll_node_t *_node_ptr = NULL;                                           \
     	node_ptr = list_ptr->head;                                              \
     	for(; node_ptr!= NULL; node_ptr = _node_ptr){                           \
     		if(!node_ptr) break;                                                \
     		_node_ptr = node_ptr->right;
     #define ITERATE_LIST_END  }}
    Use case: macro's are powerful, since they're just copy-paste!
     ITERATIVE_LIST_BEGIN(stu_ptr, node_ptr){
     	data = ...
     	sdfasd
     }ITERATIVE_LIST_END
    • why do you need another define?
      • As can be seen in the use case, without defining another end, text expansion is not gonna work right. So Always need a dumb iterate macro, and always include 2 macros
    • This is all about text substitution.
  • E.g, Binary search tree

     	tree_node_t *treenodeptr = NULL; 
     	ITERATE_BST_BEGIN(tree, treenodeptr){
     		//DO_STUFF
     	}ITERATE_BST_END
     	#define ITERATE_BST_BEGIN(tree, treenodeptr)	\
     	{ treenodeptr = NULL; 
     	

Null Structure

  • Definition:

    • returns an empty object with abstract interface and empty body, instead of a null pointer
    • Used for testing
    • Allows the code not to consider "NULL pointer or exception" when nothing is to be returned.
    • NUll object's address is 0
    • ALl members are assigned memory, but not initialized.
  • Example

    • If you traverse down a tree to calculate tree size, when you hit a leaf node, instead of handling leaf nodes in the overall traversal, you have leaf nodes to return 0

    • Macro for calculating the "field offset"(the previous field's size) of a specific field c #define offset_of(struct_name, field_name) \ (unsigned int)& ((struct_name *) 0) -> field_name offset = offset_of(Obj, salary);

      • Null structure can make Any structure start at address 0.ptr = (struct_name*) 0
      • The structure is not empty, so you can still access it? ptr -> field
      • so the address of that field is the offset &(ptr -> field)
      • Then we can typecast the new address to unsigned int
      • precedence: -> is tier 1, & is tier 2. * is tier 2.

Glued Library

  • Definition:

    • An object contains a "sticker", which contains the addresses of the other neighbor's addresses in a tree, etc.
    • It's widely used in industry
    • The benefits: memory management is handled by the node itself. The sticker is very convenient.
      • Eg, a traditional linked list need to manage the nodes's memory by themselves. When you want to delete a node (reference) from multiple linkedlist, each linked list needs to worry about if no other DLL have deleted it.
    • The cons: you must know how many stickers you need.

⚠️ **GitHub.com Fallback** ⚠️