/**
 * THIS FILE IS AUTOMATICALLY GENERATED. ANY MODIFICATIONS TO IT WILL BE OVERWRITTEN.
 */

#include "./dbl_list.h"
#include "../../common/assert/assert.h"
#include "../../common/aliases/aliases.h"
#include "../../common/platform/platform.h"
#include <stddef.h>

wapp_intern VoidPList void_ptr_node_to_list(VoidPNode *node);
wapp_intern Str8List str8_node_to_list(Str8Node *node);
wapp_intern B8List b8_node_to_list(B8Node *node);
wapp_intern CharList char_node_to_list(CharNode *node);
wapp_intern C8List c8_node_to_list(C8Node *node);
wapp_intern C16List c16_node_to_list(C16Node *node);
wapp_intern C32List c32_node_to_list(C32Node *node);
wapp_intern I8List i8_node_to_list(I8Node *node);
wapp_intern I16List i16_node_to_list(I16Node *node);
wapp_intern I32List i32_node_to_list(I32Node *node);
wapp_intern I64List i64_node_to_list(I64Node *node);
wapp_intern U8List u8_node_to_list(U8Node *node);
wapp_intern U16List u16_node_to_list(U16Node *node);
wapp_intern U32List u32_node_to_list(U32Node *node);
wapp_intern U64List u64_node_to_list(U64Node *node);
wapp_intern F32List f32_node_to_list(F32Node *node);
wapp_intern F64List f64_node_to_list(F64Node *node);
wapp_intern F128List f128_node_to_list(F128Node *node);
wapp_intern IptrList iptr_node_to_list(IptrNode *node);
wapp_intern UptrList uptr_node_to_list(UptrNode *node);

VoidPNode *wapp_void_ptr_list_get(const VoidPList *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  VoidPNode *output  = NULL;
  VoidPNode *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_void_ptr_list_push_front(VoidPList *list, VoidPNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  VoidPList node_list = void_ptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  VoidPNode *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_void_ptr_list_push_back(VoidPList *list, VoidPNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  VoidPList node_list = void_ptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  VoidPNode *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_void_ptr_list_insert(VoidPList *list, VoidPNode *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_void_ptr_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_void_ptr_list_push_back(list, node);
    return;
  }

  VoidPNode *dst_node = wapp_void_ptr_list_get(list, index);
  if (!dst_node) {
    return;
  }

  VoidPList node_list = void_ptr_node_to_list(node);

  list->node_count += node_list.node_count;

  VoidPNode *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

VoidPNode *wapp_void_ptr_list_pop_front(VoidPList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  VoidPNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_VOID_PTR_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (VoidPList){0};
    goto RETURN_VOID_PTR_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_VOID_PTR_LIST_POP_FRONT:
  return output;
}

VoidPNode *wapp_void_ptr_list_pop_back(VoidPList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  VoidPNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_VOID_PTR_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (VoidPList){0};
    goto RETURN_VOID_PTR_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_VOID_PTR_LIST_POP_BACK:
  return output;
}

VoidPNode *wapp_void_ptr_list_remove(VoidPList *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  VoidPNode *output = NULL;

  if (index == 0) {
    output = wapp_void_ptr_list_pop_front(list);
    goto RETURN_VOID_PTR_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_void_ptr_list_pop_back(list);
    goto RETURN_VOID_PTR_LIST_REMOVE;
  }

  output = wapp_void_ptr_list_get(list, index);
  if (!output) {
    goto RETURN_VOID_PTR_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_VOID_PTR_LIST_REMOVE:
  return output;
}

void wapp_void_ptr_list_empty(VoidPList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_void_ptr_list_pop_back(list);
  }
}

Str8Node *wapp_str8_list_get(const Str8List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  Str8Node *output  = NULL;
  Str8Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_str8_list_push_front(Str8List *list, Str8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  Str8List node_list = str8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  Str8Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_str8_list_push_back(Str8List *list, Str8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  Str8List node_list = str8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  Str8Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_str8_list_insert(Str8List *list, Str8Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_str8_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_str8_list_push_back(list, node);
    return;
  }

  Str8Node *dst_node = wapp_str8_list_get(list, index);
  if (!dst_node) {
    return;
  }

  Str8List node_list = str8_node_to_list(node);

  list->node_count += node_list.node_count;

  Str8Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

Str8Node *wapp_str8_list_pop_front(Str8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  Str8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_STR8_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (Str8List){0};
    goto RETURN_STR8_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_STR8_LIST_POP_FRONT:
  return output;
}

Str8Node *wapp_str8_list_pop_back(Str8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  Str8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_STR8_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (Str8List){0};
    goto RETURN_STR8_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_STR8_LIST_POP_BACK:
  return output;
}

Str8Node *wapp_str8_list_remove(Str8List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  Str8Node *output = NULL;

  if (index == 0) {
    output = wapp_str8_list_pop_front(list);
    goto RETURN_STR8_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_str8_list_pop_back(list);
    goto RETURN_STR8_LIST_REMOVE;
  }

  output = wapp_str8_list_get(list, index);
  if (!output) {
    goto RETURN_STR8_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_STR8_LIST_REMOVE:
  return output;
}

void wapp_str8_list_empty(Str8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_str8_list_pop_back(list);
  }
}

B8Node *wapp_b8_list_get(const B8List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  B8Node *output  = NULL;
  B8Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_b8_list_push_front(B8List *list, B8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  B8List node_list = b8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  B8Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_b8_list_push_back(B8List *list, B8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  B8List node_list = b8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  B8Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_b8_list_insert(B8List *list, B8Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_b8_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_b8_list_push_back(list, node);
    return;
  }

  B8Node *dst_node = wapp_b8_list_get(list, index);
  if (!dst_node) {
    return;
  }

  B8List node_list = b8_node_to_list(node);

  list->node_count += node_list.node_count;

  B8Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

B8Node *wapp_b8_list_pop_front(B8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  B8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_B8_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (B8List){0};
    goto RETURN_B8_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_B8_LIST_POP_FRONT:
  return output;
}

B8Node *wapp_b8_list_pop_back(B8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  B8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_B8_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (B8List){0};
    goto RETURN_B8_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_B8_LIST_POP_BACK:
  return output;
}

B8Node *wapp_b8_list_remove(B8List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  B8Node *output = NULL;

  if (index == 0) {
    output = wapp_b8_list_pop_front(list);
    goto RETURN_B8_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_b8_list_pop_back(list);
    goto RETURN_B8_LIST_REMOVE;
  }

  output = wapp_b8_list_get(list, index);
  if (!output) {
    goto RETURN_B8_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_B8_LIST_REMOVE:
  return output;
}

void wapp_b8_list_empty(B8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_b8_list_pop_back(list);
  }
}

CharNode *wapp_char_list_get(const CharList *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  CharNode *output  = NULL;
  CharNode *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_char_list_push_front(CharList *list, CharNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  CharList node_list = char_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  CharNode *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_char_list_push_back(CharList *list, CharNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  CharList node_list = char_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  CharNode *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_char_list_insert(CharList *list, CharNode *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_char_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_char_list_push_back(list, node);
    return;
  }

  CharNode *dst_node = wapp_char_list_get(list, index);
  if (!dst_node) {
    return;
  }

  CharList node_list = char_node_to_list(node);

  list->node_count += node_list.node_count;

  CharNode *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

CharNode *wapp_char_list_pop_front(CharList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  CharNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_CHAR_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (CharList){0};
    goto RETURN_CHAR_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_CHAR_LIST_POP_FRONT:
  return output;
}

CharNode *wapp_char_list_pop_back(CharList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  CharNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_CHAR_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (CharList){0};
    goto RETURN_CHAR_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_CHAR_LIST_POP_BACK:
  return output;
}

CharNode *wapp_char_list_remove(CharList *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  CharNode *output = NULL;

  if (index == 0) {
    output = wapp_char_list_pop_front(list);
    goto RETURN_CHAR_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_char_list_pop_back(list);
    goto RETURN_CHAR_LIST_REMOVE;
  }

  output = wapp_char_list_get(list, index);
  if (!output) {
    goto RETURN_CHAR_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_CHAR_LIST_REMOVE:
  return output;
}

void wapp_char_list_empty(CharList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_char_list_pop_back(list);
  }
}

C8Node *wapp_c8_list_get(const C8List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  C8Node *output  = NULL;
  C8Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_c8_list_push_front(C8List *list, C8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C8List node_list = c8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C8Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_c8_list_push_back(C8List *list, C8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C8List node_list = c8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C8Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_c8_list_insert(C8List *list, C8Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_c8_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_c8_list_push_back(list, node);
    return;
  }

  C8Node *dst_node = wapp_c8_list_get(list, index);
  if (!dst_node) {
    return;
  }

  C8List node_list = c8_node_to_list(node);

  list->node_count += node_list.node_count;

  C8Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

C8Node *wapp_c8_list_pop_front(C8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C8_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (C8List){0};
    goto RETURN_C8_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_C8_LIST_POP_FRONT:
  return output;
}

C8Node *wapp_c8_list_pop_back(C8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C8_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (C8List){0};
    goto RETURN_C8_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_C8_LIST_POP_BACK:
  return output;
}

C8Node *wapp_c8_list_remove(C8List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C8Node *output = NULL;

  if (index == 0) {
    output = wapp_c8_list_pop_front(list);
    goto RETURN_C8_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_c8_list_pop_back(list);
    goto RETURN_C8_LIST_REMOVE;
  }

  output = wapp_c8_list_get(list, index);
  if (!output) {
    goto RETURN_C8_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_C8_LIST_REMOVE:
  return output;
}

void wapp_c8_list_empty(C8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_c8_list_pop_back(list);
  }
}

C16Node *wapp_c16_list_get(const C16List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  C16Node *output  = NULL;
  C16Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_c16_list_push_front(C16List *list, C16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C16List node_list = c16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C16Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_c16_list_push_back(C16List *list, C16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C16List node_list = c16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C16Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_c16_list_insert(C16List *list, C16Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_c16_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_c16_list_push_back(list, node);
    return;
  }

  C16Node *dst_node = wapp_c16_list_get(list, index);
  if (!dst_node) {
    return;
  }

  C16List node_list = c16_node_to_list(node);

  list->node_count += node_list.node_count;

  C16Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

C16Node *wapp_c16_list_pop_front(C16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C16_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (C16List){0};
    goto RETURN_C16_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_C16_LIST_POP_FRONT:
  return output;
}

C16Node *wapp_c16_list_pop_back(C16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C16_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (C16List){0};
    goto RETURN_C16_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_C16_LIST_POP_BACK:
  return output;
}

C16Node *wapp_c16_list_remove(C16List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C16Node *output = NULL;

  if (index == 0) {
    output = wapp_c16_list_pop_front(list);
    goto RETURN_C16_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_c16_list_pop_back(list);
    goto RETURN_C16_LIST_REMOVE;
  }

  output = wapp_c16_list_get(list, index);
  if (!output) {
    goto RETURN_C16_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_C16_LIST_REMOVE:
  return output;
}

void wapp_c16_list_empty(C16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_c16_list_pop_back(list);
  }
}

C32Node *wapp_c32_list_get(const C32List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  C32Node *output  = NULL;
  C32Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_c32_list_push_front(C32List *list, C32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C32List node_list = c32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C32Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_c32_list_push_back(C32List *list, C32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  C32List node_list = c32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  C32Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_c32_list_insert(C32List *list, C32Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_c32_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_c32_list_push_back(list, node);
    return;
  }

  C32Node *dst_node = wapp_c32_list_get(list, index);
  if (!dst_node) {
    return;
  }

  C32List node_list = c32_node_to_list(node);

  list->node_count += node_list.node_count;

  C32Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

C32Node *wapp_c32_list_pop_front(C32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C32_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (C32List){0};
    goto RETURN_C32_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_C32_LIST_POP_FRONT:
  return output;
}

C32Node *wapp_c32_list_pop_back(C32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_C32_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (C32List){0};
    goto RETURN_C32_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_C32_LIST_POP_BACK:
  return output;
}

C32Node *wapp_c32_list_remove(C32List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  C32Node *output = NULL;

  if (index == 0) {
    output = wapp_c32_list_pop_front(list);
    goto RETURN_C32_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_c32_list_pop_back(list);
    goto RETURN_C32_LIST_REMOVE;
  }

  output = wapp_c32_list_get(list, index);
  if (!output) {
    goto RETURN_C32_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_C32_LIST_REMOVE:
  return output;
}

void wapp_c32_list_empty(C32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_c32_list_pop_back(list);
  }
}

I8Node *wapp_i8_list_get(const I8List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  I8Node *output  = NULL;
  I8Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_i8_list_push_front(I8List *list, I8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I8List node_list = i8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I8Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_i8_list_push_back(I8List *list, I8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I8List node_list = i8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I8Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_i8_list_insert(I8List *list, I8Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_i8_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_i8_list_push_back(list, node);
    return;
  }

  I8Node *dst_node = wapp_i8_list_get(list, index);
  if (!dst_node) {
    return;
  }

  I8List node_list = i8_node_to_list(node);

  list->node_count += node_list.node_count;

  I8Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

I8Node *wapp_i8_list_pop_front(I8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I8_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (I8List){0};
    goto RETURN_I8_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_I8_LIST_POP_FRONT:
  return output;
}

I8Node *wapp_i8_list_pop_back(I8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I8_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (I8List){0};
    goto RETURN_I8_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_I8_LIST_POP_BACK:
  return output;
}

I8Node *wapp_i8_list_remove(I8List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I8Node *output = NULL;

  if (index == 0) {
    output = wapp_i8_list_pop_front(list);
    goto RETURN_I8_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_i8_list_pop_back(list);
    goto RETURN_I8_LIST_REMOVE;
  }

  output = wapp_i8_list_get(list, index);
  if (!output) {
    goto RETURN_I8_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_I8_LIST_REMOVE:
  return output;
}

void wapp_i8_list_empty(I8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_i8_list_pop_back(list);
  }
}

I16Node *wapp_i16_list_get(const I16List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  I16Node *output  = NULL;
  I16Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_i16_list_push_front(I16List *list, I16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I16List node_list = i16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I16Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_i16_list_push_back(I16List *list, I16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I16List node_list = i16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I16Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_i16_list_insert(I16List *list, I16Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_i16_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_i16_list_push_back(list, node);
    return;
  }

  I16Node *dst_node = wapp_i16_list_get(list, index);
  if (!dst_node) {
    return;
  }

  I16List node_list = i16_node_to_list(node);

  list->node_count += node_list.node_count;

  I16Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

I16Node *wapp_i16_list_pop_front(I16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I16_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (I16List){0};
    goto RETURN_I16_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_I16_LIST_POP_FRONT:
  return output;
}

I16Node *wapp_i16_list_pop_back(I16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I16_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (I16List){0};
    goto RETURN_I16_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_I16_LIST_POP_BACK:
  return output;
}

I16Node *wapp_i16_list_remove(I16List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I16Node *output = NULL;

  if (index == 0) {
    output = wapp_i16_list_pop_front(list);
    goto RETURN_I16_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_i16_list_pop_back(list);
    goto RETURN_I16_LIST_REMOVE;
  }

  output = wapp_i16_list_get(list, index);
  if (!output) {
    goto RETURN_I16_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_I16_LIST_REMOVE:
  return output;
}

void wapp_i16_list_empty(I16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_i16_list_pop_back(list);
  }
}

I32Node *wapp_i32_list_get(const I32List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  I32Node *output  = NULL;
  I32Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_i32_list_push_front(I32List *list, I32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I32List node_list = i32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I32Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_i32_list_push_back(I32List *list, I32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I32List node_list = i32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I32Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_i32_list_insert(I32List *list, I32Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_i32_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_i32_list_push_back(list, node);
    return;
  }

  I32Node *dst_node = wapp_i32_list_get(list, index);
  if (!dst_node) {
    return;
  }

  I32List node_list = i32_node_to_list(node);

  list->node_count += node_list.node_count;

  I32Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

I32Node *wapp_i32_list_pop_front(I32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I32_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (I32List){0};
    goto RETURN_I32_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_I32_LIST_POP_FRONT:
  return output;
}

I32Node *wapp_i32_list_pop_back(I32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I32_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (I32List){0};
    goto RETURN_I32_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_I32_LIST_POP_BACK:
  return output;
}

I32Node *wapp_i32_list_remove(I32List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I32Node *output = NULL;

  if (index == 0) {
    output = wapp_i32_list_pop_front(list);
    goto RETURN_I32_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_i32_list_pop_back(list);
    goto RETURN_I32_LIST_REMOVE;
  }

  output = wapp_i32_list_get(list, index);
  if (!output) {
    goto RETURN_I32_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_I32_LIST_REMOVE:
  return output;
}

void wapp_i32_list_empty(I32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_i32_list_pop_back(list);
  }
}

I64Node *wapp_i64_list_get(const I64List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  I64Node *output  = NULL;
  I64Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_i64_list_push_front(I64List *list, I64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I64List node_list = i64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I64Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_i64_list_push_back(I64List *list, I64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  I64List node_list = i64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  I64Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_i64_list_insert(I64List *list, I64Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_i64_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_i64_list_push_back(list, node);
    return;
  }

  I64Node *dst_node = wapp_i64_list_get(list, index);
  if (!dst_node) {
    return;
  }

  I64List node_list = i64_node_to_list(node);

  list->node_count += node_list.node_count;

  I64Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

I64Node *wapp_i64_list_pop_front(I64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I64_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (I64List){0};
    goto RETURN_I64_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_I64_LIST_POP_FRONT:
  return output;
}

I64Node *wapp_i64_list_pop_back(I64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_I64_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (I64List){0};
    goto RETURN_I64_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_I64_LIST_POP_BACK:
  return output;
}

I64Node *wapp_i64_list_remove(I64List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  I64Node *output = NULL;

  if (index == 0) {
    output = wapp_i64_list_pop_front(list);
    goto RETURN_I64_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_i64_list_pop_back(list);
    goto RETURN_I64_LIST_REMOVE;
  }

  output = wapp_i64_list_get(list, index);
  if (!output) {
    goto RETURN_I64_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_I64_LIST_REMOVE:
  return output;
}

void wapp_i64_list_empty(I64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_i64_list_pop_back(list);
  }
}

U8Node *wapp_u8_list_get(const U8List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  U8Node *output  = NULL;
  U8Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_u8_list_push_front(U8List *list, U8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U8List node_list = u8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U8Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_u8_list_push_back(U8List *list, U8Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U8List node_list = u8_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U8Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_u8_list_insert(U8List *list, U8Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_u8_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_u8_list_push_back(list, node);
    return;
  }

  U8Node *dst_node = wapp_u8_list_get(list, index);
  if (!dst_node) {
    return;
  }

  U8List node_list = u8_node_to_list(node);

  list->node_count += node_list.node_count;

  U8Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

U8Node *wapp_u8_list_pop_front(U8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U8_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (U8List){0};
    goto RETURN_U8_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_U8_LIST_POP_FRONT:
  return output;
}

U8Node *wapp_u8_list_pop_back(U8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U8Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U8_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (U8List){0};
    goto RETURN_U8_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_U8_LIST_POP_BACK:
  return output;
}

U8Node *wapp_u8_list_remove(U8List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U8Node *output = NULL;

  if (index == 0) {
    output = wapp_u8_list_pop_front(list);
    goto RETURN_U8_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_u8_list_pop_back(list);
    goto RETURN_U8_LIST_REMOVE;
  }

  output = wapp_u8_list_get(list, index);
  if (!output) {
    goto RETURN_U8_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_U8_LIST_REMOVE:
  return output;
}

void wapp_u8_list_empty(U8List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_u8_list_pop_back(list);
  }
}

U16Node *wapp_u16_list_get(const U16List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  U16Node *output  = NULL;
  U16Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_u16_list_push_front(U16List *list, U16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U16List node_list = u16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U16Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_u16_list_push_back(U16List *list, U16Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U16List node_list = u16_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U16Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_u16_list_insert(U16List *list, U16Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_u16_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_u16_list_push_back(list, node);
    return;
  }

  U16Node *dst_node = wapp_u16_list_get(list, index);
  if (!dst_node) {
    return;
  }

  U16List node_list = u16_node_to_list(node);

  list->node_count += node_list.node_count;

  U16Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

U16Node *wapp_u16_list_pop_front(U16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U16_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (U16List){0};
    goto RETURN_U16_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_U16_LIST_POP_FRONT:
  return output;
}

U16Node *wapp_u16_list_pop_back(U16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U16Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U16_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (U16List){0};
    goto RETURN_U16_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_U16_LIST_POP_BACK:
  return output;
}

U16Node *wapp_u16_list_remove(U16List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U16Node *output = NULL;

  if (index == 0) {
    output = wapp_u16_list_pop_front(list);
    goto RETURN_U16_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_u16_list_pop_back(list);
    goto RETURN_U16_LIST_REMOVE;
  }

  output = wapp_u16_list_get(list, index);
  if (!output) {
    goto RETURN_U16_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_U16_LIST_REMOVE:
  return output;
}

void wapp_u16_list_empty(U16List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_u16_list_pop_back(list);
  }
}

U32Node *wapp_u32_list_get(const U32List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  U32Node *output  = NULL;
  U32Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_u32_list_push_front(U32List *list, U32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U32List node_list = u32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U32Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_u32_list_push_back(U32List *list, U32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U32List node_list = u32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U32Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_u32_list_insert(U32List *list, U32Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_u32_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_u32_list_push_back(list, node);
    return;
  }

  U32Node *dst_node = wapp_u32_list_get(list, index);
  if (!dst_node) {
    return;
  }

  U32List node_list = u32_node_to_list(node);

  list->node_count += node_list.node_count;

  U32Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

U32Node *wapp_u32_list_pop_front(U32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U32_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (U32List){0};
    goto RETURN_U32_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_U32_LIST_POP_FRONT:
  return output;
}

U32Node *wapp_u32_list_pop_back(U32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U32_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (U32List){0};
    goto RETURN_U32_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_U32_LIST_POP_BACK:
  return output;
}

U32Node *wapp_u32_list_remove(U32List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U32Node *output = NULL;

  if (index == 0) {
    output = wapp_u32_list_pop_front(list);
    goto RETURN_U32_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_u32_list_pop_back(list);
    goto RETURN_U32_LIST_REMOVE;
  }

  output = wapp_u32_list_get(list, index);
  if (!output) {
    goto RETURN_U32_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_U32_LIST_REMOVE:
  return output;
}

void wapp_u32_list_empty(U32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_u32_list_pop_back(list);
  }
}

U64Node *wapp_u64_list_get(const U64List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  U64Node *output  = NULL;
  U64Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_u64_list_push_front(U64List *list, U64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U64List node_list = u64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U64Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_u64_list_push_back(U64List *list, U64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  U64List node_list = u64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  U64Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_u64_list_insert(U64List *list, U64Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_u64_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_u64_list_push_back(list, node);
    return;
  }

  U64Node *dst_node = wapp_u64_list_get(list, index);
  if (!dst_node) {
    return;
  }

  U64List node_list = u64_node_to_list(node);

  list->node_count += node_list.node_count;

  U64Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

U64Node *wapp_u64_list_pop_front(U64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U64_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (U64List){0};
    goto RETURN_U64_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_U64_LIST_POP_FRONT:
  return output;
}

U64Node *wapp_u64_list_pop_back(U64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_U64_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (U64List){0};
    goto RETURN_U64_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_U64_LIST_POP_BACK:
  return output;
}

U64Node *wapp_u64_list_remove(U64List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  U64Node *output = NULL;

  if (index == 0) {
    output = wapp_u64_list_pop_front(list);
    goto RETURN_U64_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_u64_list_pop_back(list);
    goto RETURN_U64_LIST_REMOVE;
  }

  output = wapp_u64_list_get(list, index);
  if (!output) {
    goto RETURN_U64_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_U64_LIST_REMOVE:
  return output;
}

void wapp_u64_list_empty(U64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_u64_list_pop_back(list);
  }
}

F32Node *wapp_f32_list_get(const F32List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  F32Node *output  = NULL;
  F32Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_f32_list_push_front(F32List *list, F32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F32List node_list = f32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F32Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_f32_list_push_back(F32List *list, F32Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F32List node_list = f32_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F32Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_f32_list_insert(F32List *list, F32Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_f32_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_f32_list_push_back(list, node);
    return;
  }

  F32Node *dst_node = wapp_f32_list_get(list, index);
  if (!dst_node) {
    return;
  }

  F32List node_list = f32_node_to_list(node);

  list->node_count += node_list.node_count;

  F32Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

F32Node *wapp_f32_list_pop_front(F32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F32_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (F32List){0};
    goto RETURN_F32_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_F32_LIST_POP_FRONT:
  return output;
}

F32Node *wapp_f32_list_pop_back(F32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F32Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F32_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (F32List){0};
    goto RETURN_F32_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_F32_LIST_POP_BACK:
  return output;
}

F32Node *wapp_f32_list_remove(F32List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F32Node *output = NULL;

  if (index == 0) {
    output = wapp_f32_list_pop_front(list);
    goto RETURN_F32_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_f32_list_pop_back(list);
    goto RETURN_F32_LIST_REMOVE;
  }

  output = wapp_f32_list_get(list, index);
  if (!output) {
    goto RETURN_F32_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_F32_LIST_REMOVE:
  return output;
}

void wapp_f32_list_empty(F32List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_f32_list_pop_back(list);
  }
}

F64Node *wapp_f64_list_get(const F64List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  F64Node *output  = NULL;
  F64Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_f64_list_push_front(F64List *list, F64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F64List node_list = f64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F64Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_f64_list_push_back(F64List *list, F64Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F64List node_list = f64_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F64Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_f64_list_insert(F64List *list, F64Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_f64_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_f64_list_push_back(list, node);
    return;
  }

  F64Node *dst_node = wapp_f64_list_get(list, index);
  if (!dst_node) {
    return;
  }

  F64List node_list = f64_node_to_list(node);

  list->node_count += node_list.node_count;

  F64Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

F64Node *wapp_f64_list_pop_front(F64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F64_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (F64List){0};
    goto RETURN_F64_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_F64_LIST_POP_FRONT:
  return output;
}

F64Node *wapp_f64_list_pop_back(F64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F64Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F64_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (F64List){0};
    goto RETURN_F64_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_F64_LIST_POP_BACK:
  return output;
}

F64Node *wapp_f64_list_remove(F64List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F64Node *output = NULL;

  if (index == 0) {
    output = wapp_f64_list_pop_front(list);
    goto RETURN_F64_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_f64_list_pop_back(list);
    goto RETURN_F64_LIST_REMOVE;
  }

  output = wapp_f64_list_get(list, index);
  if (!output) {
    goto RETURN_F64_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_F64_LIST_REMOVE:
  return output;
}

void wapp_f64_list_empty(F64List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_f64_list_pop_back(list);
  }
}

F128Node *wapp_f128_list_get(const F128List *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  F128Node *output  = NULL;
  F128Node *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_f128_list_push_front(F128List *list, F128Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F128List node_list = f128_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F128Node *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_f128_list_push_back(F128List *list, F128Node *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  F128List node_list = f128_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  F128Node *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_f128_list_insert(F128List *list, F128Node *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_f128_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_f128_list_push_back(list, node);
    return;
  }

  F128Node *dst_node = wapp_f128_list_get(list, index);
  if (!dst_node) {
    return;
  }

  F128List node_list = f128_node_to_list(node);

  list->node_count += node_list.node_count;

  F128Node *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

F128Node *wapp_f128_list_pop_front(F128List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F128Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F128_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (F128List){0};
    goto RETURN_F128_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_F128_LIST_POP_FRONT:
  return output;
}

F128Node *wapp_f128_list_pop_back(F128List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F128Node *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_F128_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (F128List){0};
    goto RETURN_F128_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_F128_LIST_POP_BACK:
  return output;
}

F128Node *wapp_f128_list_remove(F128List *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  F128Node *output = NULL;

  if (index == 0) {
    output = wapp_f128_list_pop_front(list);
    goto RETURN_F128_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_f128_list_pop_back(list);
    goto RETURN_F128_LIST_REMOVE;
  }

  output = wapp_f128_list_get(list, index);
  if (!output) {
    goto RETURN_F128_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_F128_LIST_REMOVE:
  return output;
}

void wapp_f128_list_empty(F128List *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_f128_list_pop_back(list);
  }
}

IptrNode *wapp_iptr_list_get(const IptrList *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  IptrNode *output  = NULL;
  IptrNode *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_iptr_list_push_front(IptrList *list, IptrNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  IptrList node_list = iptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  IptrNode *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_iptr_list_push_back(IptrList *list, IptrNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  IptrList node_list = iptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  IptrNode *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_iptr_list_insert(IptrList *list, IptrNode *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_iptr_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_iptr_list_push_back(list, node);
    return;
  }

  IptrNode *dst_node = wapp_iptr_list_get(list, index);
  if (!dst_node) {
    return;
  }

  IptrList node_list = iptr_node_to_list(node);

  list->node_count += node_list.node_count;

  IptrNode *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

IptrNode *wapp_iptr_list_pop_front(IptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  IptrNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_IPTR_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (IptrList){0};
    goto RETURN_IPTR_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_IPTR_LIST_POP_FRONT:
  return output;
}

IptrNode *wapp_iptr_list_pop_back(IptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  IptrNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_IPTR_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (IptrList){0};
    goto RETURN_IPTR_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_IPTR_LIST_POP_BACK:
  return output;
}

IptrNode *wapp_iptr_list_remove(IptrList *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  IptrNode *output = NULL;

  if (index == 0) {
    output = wapp_iptr_list_pop_front(list);
    goto RETURN_IPTR_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_iptr_list_pop_back(list);
    goto RETURN_IPTR_LIST_REMOVE;
  }

  output = wapp_iptr_list_get(list, index);
  if (!output) {
    goto RETURN_IPTR_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_IPTR_LIST_REMOVE:
  return output;
}

void wapp_iptr_list_empty(IptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_iptr_list_pop_back(list);
  }
}

UptrNode *wapp_uptr_list_get(const UptrList *list, u64 index) {
  wapp_runtime_assert(index < list->node_count, "`index` is out of bounds");

  UptrNode *output  = NULL;
  UptrNode *current = list->first;
  for (u64 i = 1; i <= index; ++i) {
    current = current->next;
  }

  output = current;

  return output;
}

void wapp_uptr_list_push_front(UptrList *list, UptrNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  UptrList node_list = uptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  UptrNode *first = list->first;
  if (first) {
    first->prev = node_list.last;
  }

  list->first          = node_list.first;
  node_list.last->next = first;
}

void wapp_uptr_list_push_back(UptrList *list, UptrNode *node) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  UptrList node_list = uptr_node_to_list(node);

  if (list->node_count == 0) {
    *list = node_list;
    return;
  }

  list->node_count += node_list.node_count;

  UptrNode *last = list->last;
  if (last) {
    last->next = node_list.first;
  }

  list->last            = node_list.last;
  node_list.first->prev = last;
}

void wapp_uptr_list_insert(UptrList *list, UptrNode *node, u64 index) {
  wapp_debug_assert(list != NULL && node != NULL && (node->item) != NULL, "`list`, `node` and `node->item` should not be NULL");

  if (index == 0) {
    wapp_uptr_list_push_front(list, node);
    return;
  } else if (index == list->node_count) {
    wapp_uptr_list_push_back(list, node);
    return;
  }

  UptrNode *dst_node = wapp_uptr_list_get(list, index);
  if (!dst_node) {
    return;
  }

  UptrList node_list = uptr_node_to_list(node);

  list->node_count += node_list.node_count;

  UptrNode *prev = dst_node->prev;

  dst_node->prev = node_list.last;
  prev->next     = node_list.first;

  node_list.first->prev = prev;
  node_list.last->next  = dst_node;
}

UptrNode *wapp_uptr_list_pop_front(UptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  UptrNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_UPTR_LIST_POP_FRONT;
  }

  output = list->first;

  if (list->node_count == 1) {
    *list = (UptrList){0};
    goto RETURN_UPTR_LIST_POP_FRONT;
  }

  --(list->node_count);
  list->first = output->next;

  output->prev = output->next = NULL;

RETURN_UPTR_LIST_POP_FRONT:
  return output;
}

UptrNode *wapp_uptr_list_pop_back(UptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  UptrNode *output = NULL;

  if (list->node_count == 0) {
    goto RETURN_UPTR_LIST_POP_BACK;
  }

  output = list->last;

  if (list->node_count == 1) {
    *list = (UptrList){0};
    goto RETURN_UPTR_LIST_POP_BACK;
  }

  --(list->node_count);
  list->last = output->prev;

  output->prev = output->next = NULL;

RETURN_UPTR_LIST_POP_BACK:
  return output;
}

UptrNode *wapp_uptr_list_remove(UptrList *list, u64 index) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  UptrNode *output = NULL;

  if (index == 0) {
    output = wapp_uptr_list_pop_front(list);
    goto RETURN_UPTR_LIST_REMOVE;
  } else if (index == list->node_count) {
    output = wapp_uptr_list_pop_back(list);
    goto RETURN_UPTR_LIST_REMOVE;
  }

  output = wapp_uptr_list_get(list, index);
  if (!output) {
    goto RETURN_UPTR_LIST_REMOVE;
  }

  output->prev->next = output->next;
  output->next->prev = output->prev;

  --(list->node_count);

  output->prev = output->next = NULL;

RETURN_UPTR_LIST_REMOVE:
  return output;
}

void wapp_uptr_list_empty(UptrList *list) {
  wapp_debug_assert(list != NULL, "`list` should not be NULL");

  u64 count = list->node_count;
  for (u64 i = 0; i < count; ++i) {
    wapp_uptr_list_pop_back(list);
  }
}

wapp_intern VoidPList void_ptr_node_to_list(VoidPNode *node) {
  VoidPList output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern Str8List str8_node_to_list(Str8Node *node) {
  Str8List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern B8List b8_node_to_list(B8Node *node) {
  B8List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern CharList char_node_to_list(CharNode *node) {
  CharList output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern C8List c8_node_to_list(C8Node *node) {
  C8List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern C16List c16_node_to_list(C16Node *node) {
  C16List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern C32List c32_node_to_list(C32Node *node) {
  C32List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern I8List i8_node_to_list(I8Node *node) {
  I8List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern I16List i16_node_to_list(I16Node *node) {
  I16List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern I32List i32_node_to_list(I32Node *node) {
  I32List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern I64List i64_node_to_list(I64Node *node) {
  I64List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern U8List u8_node_to_list(U8Node *node) {
  U8List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern U16List u16_node_to_list(U16Node *node) {
  U16List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern U32List u32_node_to_list(U32Node *node) {
  U32List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern U64List u64_node_to_list(U64Node *node) {
  U64List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern F32List f32_node_to_list(F32Node *node) {
  F32List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern F64List f64_node_to_list(F64Node *node) {
  F64List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern F128List f128_node_to_list(F128Node *node) {
  F128List output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern IptrList iptr_node_to_list(IptrNode *node) {
  IptrList output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

wapp_intern UptrList uptr_node_to_list(UptrNode *node) {
  UptrList output = {.first = node, .last = node, .node_count = 1};

  while (output.first->prev != NULL) {
    output.first = output.first->prev;
    ++(output.node_count);
  }

  while (output.last->next != NULL) {
    output.last = output.last->next;
    ++(output.node_count);
  }

  return output;
}

