#ifndef ULIB_LINKLIST_H_
#define ULIB_LINKLIST_H_

#define LL_APPEND(head, new) \
  do { \
    if ((new) != NULL) { \
      if ((head) != NULL) { \
        typeof((head)) __tmp; \
        (new)->next = NULL; \
        __tmp = (head); \
        while (__tmp->next != NULL) { \
          __tmp = __tmp->next; \
        } \
        __tmp->next = (new); \
      } else { \
        (new)->next = NULL; \
        (head) = (new); \
      } \
    } \
  } while(0)

#define LL_REMOVE(head, ele) \
  do { \
    if ((head) != NULL && (ele) != NULL) { \
      typeof((head)) __cur = (head); \
      typeof((head)) __prev = NULL; \
      while (__cur != NULL && __cur != (ele)) { \
        __prev = __cur; \
        __cur = __cur->next; \
      } \
      if (__cur == (ele)) { \
        if (__prev != NULL) { \
          __prev->next = __cur->next; \
        } else { \
          (head) = __cur->next; \
        } \
        (ele)->next = NULL; \
      } \
    } \
  } while(0)

#define LL_FINDPROP(head, out, propname, propvalue) \
  do { \
    (out) = NULL; \
    typeof((head)) __tmp = (head); \
    while (__tmp) { \
      if (__tmp->propname == (propvalue)) { \
        (out) = __tmp; \
        break; \
      } \
      __tmp = __tmp->next; \
    } \
  } while(0)

#define LL_FOREACH_SAFE(head, var, tmp) \
  for (var = (head), tmp = (var ? var->next : NULL); \
      var != NULL; \
      var = tmp, tmp = (var ? var->next : NULL) \
      )

#define LL_FOREACH_SAFE_IDX(head, var, tmp, idx) \
  for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
       var != NULL; \
       var = tmp, tmp = (var ? var->next : NULL), (idx)++)

#define LL_FOREACH_SAFE_IDX_LIMIT(head, var, tmp, idx, max) \
  for ((idx) = 0, var = (head), tmp = (var ? var->next : NULL); \
       var != NULL && (idx) < (max); \
       var = tmp, tmp = (var ? var->next : NULL), (idx)++)

#define LL_BACK(head, out) \
  do { \
    (out) = NULL; \
    if ((head) != NULL) { \
      typeof((head)) __tmp = (head); \
      while (__tmp->next != NULL) { \
        __tmp = __tmp->next; \
      } \
      (out) = __tmp; \
    } \
  } while(0)

#endif // ULIB_LINKLIST_H_
