From 992f2813718d8b0c303bd47194ec37402d19345a Mon Sep 17 00:00:00 2001
From: Basile Desloges <basile.desloges@cea.fr>
Date: Tue, 5 Oct 2021 16:36:29 +0200
Subject: [PATCH] [eacsl] Extract patricia trie from bittree

---
 src/plugins/e-acsl/headers/header_spec.txt    |   2 +
 .../bittree_model/e_acsl_bittree.c            | 503 ++++--------------
 .../bittree_model/e_acsl_bittree.h            |  53 +-
 .../e_acsl_bittree_observation_model.c        |  25 +-
 .../e_acsl_observation_model.c                |   1 +
 .../internals/e_acsl_patricia_trie.c          | 503 ++++++++++++++++++
 .../internals/e_acsl_patricia_trie.h          | 148 ++++++
 7 files changed, 770 insertions(+), 465 deletions(-)
 create mode 100644 src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.c
 create mode 100644 src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.h

diff --git a/src/plugins/e-acsl/headers/header_spec.txt b/src/plugins/e-acsl/headers/header_spec.txt
index 03276ab748e..c367bfc6aaf 100644
--- a/src/plugins/e-acsl/headers/header_spec.txt
+++ b/src/plugins/e-acsl/headers/header_spec.txt
@@ -56,6 +56,8 @@ share/e-acsl/observation_model/bittree_model/e_acsl_bittree_timestamp_retrieval.
 share/e-acsl/observation_model/internals/e_acsl_heap_tracking.c: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/observation_model/internals/e_acsl_heap_tracking.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/observation_model/internals/e_acsl_omodel_debug.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+share/e-acsl/observation_model/internals/e_acsl_patricia_trie.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
+share/e-acsl/observation_model/internals/e_acsl_patricia_trie.c: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/observation_model/internals/e_acsl_safe_locations.c: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/observation_model/internals/e_acsl_safe_locations.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
 share/e-acsl/observation_model/internals/e_acsl_timestamp_retrieval.h: CEA_LGPL_OR_PROPRIETARY.E_ACSL
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.c b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.c
index 4c45a5defa9..21495817006 100644
--- a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.c
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.c
@@ -22,464 +22,139 @@
 
 /*! ***********************************************************************
  * \file
- * \brief Patricia Trie API Implementation
+ * \brief Bittree implemented with a patricia trie.
  **************************************************************************/
 
-#include "../../internals/e_acsl_config.h"
-#include "../../internals/e_acsl_malloc.h"
 #include "../../internals/e_acsl_private_assert.h"
+#include "../internals/e_acsl_patricia_trie.h"
 
 #include "e_acsl_bittree.h"
 
-#if E_ACSL_OS_IS_LINUX
-#  define WORDBITS __WORDSIZE
-#elif E_ACSL_OS_IS_WINDOWS
-// On windows, __WORDSIZE is not available
-#  ifdef _WIN64
-#    define WORDBITS 64
-#  else
-#    define WORDBITS 32
-#  endif
-#else
-#  error "Unsupported OS"
-#endif
-
-static size_t mask(size_t, size_t);
-
-#if WORDBITS == 16
-
-static const size_t Tmasks[] = {0x0,    0x8000, 0xc000, 0xe000, 0xf000, 0xf800,
-                                0xfc00, 0xfe00, 0xff00, 0xff80, 0xffc0, 0xffe0,
-                                0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff};
-
-static const int Teq[] = {0,  -1, 3,   -3, 6,   -5, 7,  -7, 12,
-                          -9, 11, -11, 14, -13, 15, 16, -16};
-static const int Tneq[] = {0,  0, 1,   -2, 2,   -4, 5,   -6, 4,
-                           -8, 9, -10, 10, -12, 13, -14, -15};
-
-#elif WORDBITS == 32
-
-static const size_t Tmasks[] = {
-    0x0,        0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
-    0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
-    0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
-    0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
-    0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
-    0xfffffffc, 0xfffffffe, 0xffffffff};
-
-static const int Teq[] = {0,   -1,  3,   -3,  6,   -5,  7,   -7,  12,  -9, 11,
-                          -11, 14,  -13, 15,  -15, 24,  -17, 19,  -19, 22, -21,
-                          23,  -23, 28,  -25, 27,  -27, 30,  -29, 31,  32, -32};
-
-static const int Tneq[] = {0,  0,   1,  -2,  2,  -4,  5,  -6,  4,  -8,  9,  -10,
-                           10, -12, 13, -14, 8,  -16, 17, -18, 18, -20, 21, -22,
-                           20, -24, 25, -26, 26, -28, 29, -30, -31};
-
-#else /* WORDBITS == 64 */
-
-// clang-format off
-static const size_t Tmasks[] = {
-0x0,0x8000000000000000,0xc000000000000000,0xe000000000000000,0xf000000000000000,
-0xf800000000000000,0xfc00000000000000,0xfe00000000000000,0xff00000000000000,
-0xff80000000000000,0xffc0000000000000,0xffe0000000000000,0xfff0000000000000,
-0xfff8000000000000,0xfffc000000000000,0xfffe000000000000,0xffff000000000000,
-0xffff800000000000,0xffffc00000000000,0xffffe00000000000,0xfffff00000000000,
-0xfffff80000000000,0xfffffc0000000000,0xfffffe0000000000,0xffffff0000000000,
-0xffffff8000000000,0xffffffc000000000,0xffffffe000000000,0xfffffff000000000,
-0xfffffff800000000,0xfffffffc00000000,0xfffffffe00000000,0xffffffff00000000,
-0xffffffff80000000,0xffffffffc0000000,0xffffffffe0000000,0xfffffffff0000000,
-0xfffffffff8000000,0xfffffffffc000000,0xfffffffffe000000,0xffffffffff000000,
-0xffffffffff800000,0xffffffffffc00000,0xffffffffffe00000,0xfffffffffff00000,
-0xfffffffffff80000,0xfffffffffffc0000,0xfffffffffffe0000,0xffffffffffff0000,
-0xffffffffffff8000,0xffffffffffffc000,0xffffffffffffe000,0xfffffffffffff000,
-0xfffffffffffff800,0xfffffffffffffc00,0xfffffffffffffe00,0xffffffffffffff00,
-0xffffffffffffff80,0xffffffffffffffc0,0xffffffffffffffe0,0xfffffffffffffff0,
-0xfffffffffffffff8,0xfffffffffffffffc,0xfffffffffffffffe,0xffffffffffffffff};
-// clang-format on
-
-static const int Teq[] = {0,   -1,  3,   -3,  6,   -5,  7,   -7,  12,  -9,  11,
-                          -11, 14,  -13, 15,  -15, 24,  -17, 19,  -19, 22,  -21,
-                          23,  -23, 28,  -25, 27,  -27, 30,  -29, 31,  -31, 48,
-                          -33, 35,  -35, 38,  -37, 39,  -39, 44,  -41, 43,  -43,
-                          46,  -45, 47,  -47, 56,  -49, 51,  -51, 54,  -53, 55,
-                          -55, 60,  -57, 59,  -59, 62,  -61, 63,  64,  -64};
-
-static const int Tneq[] = {0,  0,   1,  -2,  2,  -4,  5,  -6,  4,  -8,  9,  -10,
-                           10, -12, 13, -14, 8,  -16, 17, -18, 18, -20, 21, -22,
-                           20, -24, 25, -26, 26, -28, 29, -30, 16, -32, 33, -34,
-                           34, -36, 37, -38, 36, -40, 41, -42, 42, -44, 45, -46,
-                           40, -48, 49, -50, 50, -52, 53, -54, 52, -56, 57, -58,
-                           58, -60, 61, -62, -63};
-
-#endif
-
-/*! \brief Root node of the bitree */
-static bt_node *bt_root = NULL;
-
-/* common prefix of two addresses */
-/*@ assigns \nothing;
-  @ ensures \forall int i;
-     0 <= i <= WORDBITS
-     ==> (Tmasks[i] & a) == (Tmasks[i] & b)
-     ==> \result >= Tmasks[i];
-  @ ensures (a & \result) == (b & \result);
-  @ ensures \exists int i; 0 <= i <= WORDBITS && \result == Tmasks[i];
-  @*/
-static size_t mask(size_t a, size_t b) {
-  size_t nxor = ~(a ^ b), ret;
-  int i = WORDBITS / 2; /* dichotomic search, starting in the middle */
-  /*cpt_mask++;*/
-
-  /* if the current mask matches we use transition from Teq, else from Tneq
-     we stop as soon as i is negative, meaning that we found the mask
-     a negative element i from Teq or Tneq means stop and return Tmasks[-i] */
-  /*@ loop invariant -WORDBITS <= i <= WORDBITS;
-    @ loop assigns i;
-    @*/
-  while (i > 0) {
-    //@ assert 0 < i <= WORDBITS;
-    //@ assert \valid(Tmasks+i);
-    if (nxor >= Tmasks[i])
-      //@ assert \valid(Teq+i);
-      i = Teq[i];
-    else
-      //@ assert \valid(Tneq+i);
-      i = Tneq[i];
-  }
+static pt_struct_t *bittree = NULL;
 
-  //@ assert -WORDBITS <= i <= 0;
-  ret = Tmasks[-i];
-  DASSERT((a & ret) == (b & ret));
-  return ret;
+static void *bt_get_ptr(pt_leaf_t block) {
+  return (void *)((bt_block *)block)->ptr;
 }
 
-/* called from bt_remove */
-/* the block we are looking for has to be in the tree */
-/*@ requires \valid(ptr);
-  @ requires \valid(bt_root);
-  @ assigns \nothing;
-  @ ensures \valid(\result);
-  @ ensures \result->leaf == ptr;
-  @*/
-static bt_node *bt_get_leaf_from_block(bt_block *ptr) {
-  bt_node *curr = bt_root;
-  DASSERT(bt_root != NULL);
-  DASSERT(ptr != NULL);
-
-  /*@ loop assigns curr;
-    @*/
-  while (!curr->is_leaf) {
-    // the prefix is consistent
-    DASSERT((curr->addr & curr->mask) == (ptr->ptr & curr->mask));
-    // two children
-    DASSERT(curr->left != NULL && curr->right != NULL);
-    // the prefix of one child is consistent
-    if ((curr->right->addr & curr->right->mask)
-        == (ptr->ptr & curr->right->mask))
-      curr = curr->right;
-    else if ((curr->left->addr & curr->left->mask)
-             == (ptr->ptr & curr->left->mask))
-      curr = curr->left;
-    else
-      private_abort("Unreachable\n");
-  }
-  DASSERT(curr->is_leaf);
-  DASSERT(curr->leaf == ptr);
-  return curr;
+static int bt_contains_ptr(pt_leaf_t block, void *ptr) {
+  uintptr_t ptr_ui = (uintptr_t)ptr;
+  bt_block *b = (bt_block *)block;
+  return ptr_ui >= b->ptr
+         && (ptr_ui < b->ptr + b->size || (b->size == 0 && ptr_ui == b->ptr));
 }
 
-/* remove the block from the structure */
-/* the block we are looking for has to be in the tree */
-/*@ requires \valid(ptr);
-  @*/
-static void bt_remove(bt_block *ptr) {
-  bt_node *leaf_to_delete = bt_get_leaf_from_block(ptr);
-  DASSERT(leaf_to_delete->leaf == ptr);
-
-  if (leaf_to_delete->parent == NULL)
-    // the leaf is the root
-    bt_root = NULL;
-  else {
-    bt_node *sibling, *parent;
-    parent = leaf_to_delete->parent;
-    sibling = (leaf_to_delete == parent->left) ? parent->right : parent->left;
-    DASSERT(sibling != NULL);
-    // copying all sibling's fields into the parent's
-    parent->is_leaf = sibling->is_leaf;
-    parent->addr = sibling->addr;
-    parent->mask = sibling->mask;
-    parent->left = sibling->left;
-    parent->right = sibling->right;
-    parent->leaf = sibling->leaf;
-    if (!sibling->is_leaf) {
-      sibling->left->parent = parent;
-      sibling->right->parent = parent;
-    }
-    private_free(sibling);
-    /* necessary ? -- begin */
-    if (parent->parent != NULL) {
-      parent->parent->mask =
-          mask(parent->parent->left->addr & parent->parent->left->mask,
-               parent->parent->right->addr & parent->parent->right->mask);
-    }
-    /* necessary ? -- end */
+/* erase information about initialization of a block */
+void bt_clean_block_init(bt_block *ptr) {
+  if (ptr->init_ptr != NULL) {
+    private_free(ptr->init_ptr);
+    ptr->init_ptr = NULL;
   }
-  private_free(leaf_to_delete);
+  ptr->init_bytes = 0;
 }
 
-/* called from bt_insert */
-/* the returned node will be the sibling of the soon to be added node */
-/*@ requires \valid(ptr);
-  @ requires \valid(bt_root);
-  @ assigns \nothing;
-  @ ensures \valid(\result);
-  @*/
-static bt_node *bt_most_similar_node(bt_block *ptr) {
-  bt_node *curr = bt_root;
-  size_t left_prefix, right_prefix;
-  DASSERT(ptr != NULL);
-  DASSERT(bt_root != NULL);
-
-  while (1) {
-    if (curr->is_leaf)
-      return curr;
-    DASSERT(curr->left != NULL && curr->right != NULL);
-    left_prefix = mask(curr->left->addr & curr->left->mask, ptr->ptr);
-    right_prefix = mask(curr->right->addr & curr->right->mask, ptr->ptr);
-    if (left_prefix > right_prefix)
-      curr = curr->left;
-    else if (right_prefix > left_prefix)
-      curr = curr->right;
-    else
-      return curr;
-  }
+bt_block *bt_alloc_block(uintptr_t ptr, size_t size) {
+  bt_block *res = private_malloc(sizeof(bt_block));
+  res->ptr = (uintptr_t)ptr;
+  res->size = size;
+  res->init_ptr = NULL;
+  res->init_bytes = 0;
+  res->is_readonly = 0;
+  res->is_freeable = 0;
+#ifdef E_ACSL_DEBUG
+  res->line = 0;
+  res->file = "undefined";
+#endif
+#ifdef E_ACSL_TEMPORAL
+  res->timestamp = NEW_TEMPORAL_TIMESTAMP();
+  res->temporal_shadow = (size >= sizeof(void *)) ? private_malloc(size) : NULL;
+#endif
+  return res;
 }
 
-/* add a block in the structure */
-/*@ requires \valid(ptr);
-  @*/
-static void bt_insert(bt_block *ptr) {
-  bt_node *new_leaf;
-  DASSERT(ptr != NULL);
-
-  new_leaf = private_malloc(sizeof(bt_node));
-  DASSERT(new_leaf != NULL);
-  new_leaf->is_leaf = 1;
-  new_leaf->addr = ptr->ptr;
-  new_leaf->mask = Tmasks[WORDBITS]; /* ~0ul */
-  new_leaf->left = NULL;
-  new_leaf->right = NULL;
-  new_leaf->parent = NULL;
-  new_leaf->leaf = ptr;
-
-  if (bt_root == NULL)
-    bt_root = new_leaf;
-  else {
-    bt_node *sibling = bt_most_similar_node(ptr), *parent, *aux;
-
-    DASSERT(sibling != NULL);
-    parent = private_malloc(sizeof(bt_node));
-    DASSERT(parent != NULL);
-    parent->is_leaf = 0;
-    parent->addr = sibling->addr & new_leaf->addr;
-    /*parent->mask = mask(sibling->addr & sibling->mask, ptr->ptr);*/
-    parent->leaf = NULL;
-    if (new_leaf->addr <= sibling->addr) {
-      parent->left = new_leaf;
-      parent->right = sibling;
-    } else {
-      parent->left = sibling;
-      parent->right = new_leaf;
-    }
-    new_leaf->parent = parent;
-
-    if (sibling == bt_root) {
-      parent->parent = NULL;
-      parent->mask = mask(sibling->addr & sibling->mask, ptr->ptr);
-      bt_root = parent;
-    } else {
-      if (sibling->parent->left == sibling)
-        sibling->parent->left = parent;
-      else
-        sibling->parent->right = parent;
-      parent->parent = sibling->parent;
-
-      /* necessary ? -- begin */
-      aux = parent;
-      aux->mask = mask(aux->left->addr & aux->left->mask,
-                       aux->right->addr & aux->right->mask);
-      /* necessary ? -- end */
+void bt_clean_and_free_block(bt_block *blk, int deallocate) {
+  if (blk) {
+    bt_clean_block_init(blk);
+    if (deallocate) {
+#ifdef E_ACSL_TEMPORAL
+      private_free(blk->temporal_shadow);
+#endif
+      private_free(blk);
     }
-    sibling->parent = parent;
-    if (!sibling->is_leaf)
-      sibling->mask = mask(sibling->left->addr & sibling->left->mask,
-                           sibling->right->addr & sibling->right->mask);
-
-    DASSERT((parent->left == sibling && parent->right == new_leaf)
-            || (parent->left == new_leaf && parent->right == sibling));
   }
 }
 
-/* return the block B such as: begin addr of B == ptr if such a block exists,
-   return NULL otherwise */
-/*@ assigns \nothing;
-  @ ensures \valid(\result);
-  @ ensures \result == \null || \result->ptr == (size_t)ptr;
-  @*/
-static bt_block *bt_lookup(void *ptr) {
-  bt_node *tmp = bt_root;
-  DASSERT(bt_root != NULL);
-  DASSERT(ptr != NULL);
-
-  /*@ loop assigns tmp;
-    @*/
-  while (!tmp->is_leaf) {
-    // if the ptr we are looking for does not share the prefix of tmp
-    if ((tmp->addr & tmp->mask) != ((size_t)ptr & tmp->mask))
-      return NULL;
-
-    // two children
-    DASSERT(tmp->left != NULL && tmp->right != NULL);
-    // the prefix of one child is consistent
-    if ((tmp->right->addr & tmp->right->mask)
-        == ((size_t)ptr & tmp->right->mask))
-      tmp = tmp->right;
-    else if ((tmp->left->addr & tmp->left->mask)
-             == ((size_t)ptr & tmp->left->mask))
-      tmp = tmp->left;
-    else
-      return NULL;
-  }
-
-  if (tmp->leaf->ptr != (size_t)ptr)
-    return NULL;
-  return tmp->leaf;
+void bt_free_block(bt_block *blk) {
+  bt_clean_and_free_block(blk, 1);
 }
 
-/* return the block B containing ptr, such as :
-   begin addr of B <= ptr < (begin addr + size) of B
-   or NULL if such a block does not exist */
-static bt_block *bt_find(void *ptr) {
-  bt_node *tmp = bt_root;
-  if (bt_root == NULL || ptr == NULL)
-    return NULL;
-
-  bt_node *other_choice = NULL;
-
-  while (1) {
-    if (tmp->is_leaf) {
-      /* tmp cannot contain ptr because its begin addr is higher */
-      if (tmp->addr > (size_t)ptr)
-        return NULL;
-
-      /* tmp->addr <= ptr, tmp may contain ptr
-       ptr is contained if tmp is large enough (begin addr + size) */
-      else if ((size_t)ptr < tmp->leaf->size + tmp->addr
-               || (tmp->leaf->size == 0 && (size_t)ptr == tmp->leaf->ptr))
-        return tmp->leaf;
-      /* tmp->addr <= ptr, but tmp->addr is not large enough */
-      else
-        return NULL;
-    }
-
-    DASSERT(tmp->left != NULL && tmp->right != NULL);
+/* erase all information about a block */
+static int bt_clean_with_deallocation = 0;
+static void bt_clean_block(pt_leaf_t ptr) {
+  bt_clean_and_free_block((bt_block *)ptr, bt_clean_with_deallocation);
+}
 
-    /* the right child has the highest address, so we test it first */
-    if (((size_t)tmp->right->addr & tmp->right->mask)
-        <= ((size_t)ptr & tmp->right->mask)) {
-      other_choice = tmp->left;
-      tmp = tmp->right;
-    } else if (((size_t)tmp->left->addr & tmp->left->mask)
-               <= ((size_t)ptr & tmp->left->mask))
-      tmp = tmp->left;
-    else {
-      if (other_choice == NULL)
-        return NULL;
-      else {
-        tmp = other_choice;
-        other_choice = NULL;
-      }
+static void bt_print_block(pt_leaf_t block) {
+  if (block != NULL) {
+    bt_block *b = (bt_block *)block;
+    DLOG("%a; %lu Bytes; %slitteral; [init] : %d ", (char *)b->ptr, b->size,
+         b->is_readonly ? "" : "not ", b->init_bytes);
+    if (b->init_ptr != NULL) {
+      unsigned i;
+      for (i = 0; i < b->size / 8; i++)
+        DLOG("%b ", b->init_ptr[i]);
     }
+    DLOG("\n");
   }
 }
 
-/*******************/
-/* CLEAN           */
-/*******************/
-/* erase information about initialization of a block */
-static void bt_clean_block_init(bt_block *ptr) {
-  if (ptr->init_ptr != NULL) {
-    private_free(ptr->init_ptr);
-    ptr->init_ptr = NULL;
+void bt_insert(bt_block *b) {
+  if (bittree == NULL) {
+    bittree =
+        pt_create(bt_get_ptr, bt_contains_ptr, bt_clean_block, bt_print_block);
   }
-  ptr->init_bytes = 0;
+  pt_insert(bittree, (pt_leaf_t)b);
 }
 
-/* erase all information about a block */
-static void bt_clean_block(bt_block *ptr) {
-  if (ptr) {
-    bt_clean_block_init(ptr);
-    private_free(ptr);
+void bt_remove(bt_block *b) {
+  DASSERT(bittree != NULL);
+  pt_remove(bittree, (pt_leaf_t)b);
+}
+
+bt_block *bt_lookup(void *ptr) {
+  if (bittree == NULL) {
+    return NULL;
+  } else {
+    return pt_lookup(bittree, ptr);
   }
 }
 
-/* called from bt_clean */
-/* recursively erase the content of the structure */
-static void bt_clean_rec(bt_node *ptr) {
-  if (ptr == NULL)
-    return;
-  else if (ptr->is_leaf) {
-    bt_clean_block(ptr->leaf);
-    ptr->leaf = NULL;
+bt_block *bt_find(void *ptr) {
+  if (bittree == NULL) {
+    return NULL;
   } else {
-    bt_clean_rec(ptr->left);
-    bt_clean_rec(ptr->right);
-    ptr->left = ptr->right = NULL;
+    return pt_find(bittree, ptr);
   }
-  private_free(ptr);
 }
 
-/* erase the content of the structure */
-static void bt_clean() {
-  bt_clean_rec(bt_root);
-  bt_root = NULL;
+void bt_clean() {
+  DASSERT(bittree != NULL);
+  // Indicates to `bt_clean` (called by `pt_destroy`) that it should deallocate
+  // the leaves of the tree
+  bt_clean_with_deallocation = 1;
+  pt_destroy(bittree);
+  bt_clean_with_deallocation = 0;
+  bittree = NULL;
 }
 
 /*********************/
 /* DEBUG             */
 /*********************/
 #ifdef E_ACSL_DEBUG
-static void eacsl_bt_print_block(bt_block *ptr) {
-  if (ptr != NULL) {
-    DLOG("%a; %lu Bytes; %slitteral; [init] : %d ", (char *)ptr->ptr, ptr->size,
-         ptr->is_readonly ? "" : "not ", ptr->init_bytes);
-    if (ptr->init_ptr != NULL) {
-      unsigned i;
-      for (i = 0; i < ptr->size / 8; i++)
-        DLOG("%b ", ptr->init_ptr[i]);
-    }
-    DLOG("\n");
-  }
-}
-
-static void bt_print_node(bt_node *ptr, int depth) {
-  int i;
-  if (ptr == NULL)
-    return;
-  for (i = 0; i < depth; i++)
-    DLOG("  ");
-  if (ptr->is_leaf)
-    eacsl_bt_print_block(ptr->leaf);
-  else {
-    DLOG("%p -- %p\n", (void *)ptr->mask, (void *)ptr->addr);
-    bt_print_node(ptr->left, depth + 1);
-    bt_print_node(ptr->right, depth + 1);
-  }
+void eacsl_bt_print_block(bt_block *ptr) {
+  bt_print_block((pt_leaf_t)ptr);
 }
 
-static void eacsl_bt_print_tree() {
-  DLOG("------------DEBUG\n");
-  bt_print_node(bt_root, 0);
-  DLOG("-----------------\n");
+void eacsl_bt_print_tree() {
+  pt_print(bittree);
 }
 #endif
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.h b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.h
index c17dd5f4b4d..710226ace62 100644
--- a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.h
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree.h
@@ -22,8 +22,8 @@
 
 /*! ***********************************************************************
  * \file
- * \brief Patricia Trie API
- **************************************************************************/
+ * \brief Bittree API
+***************************************************************************/
 
 #ifndef E_ACSL_BITTREE
 #define E_ACSL_BITTREE
@@ -31,9 +31,17 @@
 #include <stddef.h>
 #include <stdint.h>
 
+/* Public API {{{ */
+/* Debug */
+#ifdef E_ACSL_DEBUG
+#  define eacsl_bt_print_block export_alias(bt_print_block)
+#  define eacsl_bt_print_tree  export_alias(bt_print_tree)
+#endif
+/* }}} */
+
 /*! \brief Structure representing an allocated memory block */
 struct bt_block {
-  size_t ptr;              //!< Base address
+  uintptr_t ptr;           //!< Base address
   size_t size;             //!< Block length (in bytes)
   unsigned char *init_ptr; //!< Per-bit initialization
   size_t init_bytes;       //!< Number of initialized bytes within a block
@@ -51,54 +59,43 @@ struct bt_block {
 
 typedef struct bt_block bt_block;
 
-/*! \brief Structure representing a bittree node */
-struct bt_node {
-  int is_leaf;
-  size_t addr, mask;
-  struct bt_node *left, *right, *parent;
-  bt_block *leaf;
-};
-
-typedef struct bt_node bt_node;
-
 /*! \brief Remove a block from the structure */
-static void bt_remove(bt_block *b);
+void bt_remove(bt_block *b);
 
 /*! \brief Add a block to the structure */
-static void bt_insert(bt_block *b);
+void bt_insert(bt_block *b);
 
 /*! \brief Look-up a memory block by its base address
   NB: The function assumes that such a block exists. */
-static bt_block *bt_lookup(void *ptr);
+bt_block *bt_lookup(void *ptr);
 
 /*! \brief Find a memory block containing a given memory address
  *
  * Return block B such that:
  *  `\base_addr(B->ptr) <= ptr < (\base_addr(B->ptr) + size)`
  *  or NULL if such a block does not exist. */
-static bt_block *bt_find(void *ptr);
+bt_block *bt_find(void *ptr);
 
 /*! \brief Erase the contents of the structure */
-static void bt_clean(void);
+void bt_clean(void);
 
 /*! \brief Erase information about a block's initialization */
-static void bt_clean_block_init(bt_block *b);
+void bt_clean_block_init(bt_block *b);
+
+/*! \brief Allocates a `bt_block` for a block of memory at address `ptr` and
+    with the given size. */
+bt_block *bt_alloc_block(uintptr_t ptr, size_t size);
 
-/*! \brief Erase all information about a given block */
-static void bt_clean_block(bt_block *b);
+/*! \brief Frees the given `bt_block`. */
+void bt_free_block(bt_block *blk);
 
 #ifdef E_ACSL_DEBUG
 /*! \brief Print information about a given block */
-static void eacsl_bt_print_block(bt_block *b);
-
-/*! \brief Recursively print the contents of the bittree starting from a
- * given node */
-/*@ assigns \nothing; */
-static void bt_print_node(bt_node *ptr, int depth);
+void eacsl_bt_print_block(bt_block *b);
 
 /*! \brief Print the contents of the entire bittree */
 /*@ assigns \nothing; */
-static void bt_print();
+void eacsl_bt_print_tree();
 #endif
 
 #endif // E_ACSL_BITTREE
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree_observation_model.c b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree_observation_model.c
index ea30641feaa..3e48a5e1c20 100644
--- a/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree_observation_model.c
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/bittree_model/e_acsl_bittree_observation_model.c
@@ -39,8 +39,6 @@
 /* Public API {{{ */
 /* Debug */
 #ifdef E_ACSL_DEBUG
-#  define eacsl_bt_print_block     export_alias(bt_print_block)
-#  define eacsl_bt_print_tree      export_alias(bt_print_tree)
 #  define eacsl_block_info         export_alias(block_info)
 #  define eacsl_store_block_debug  export_alias(store_block_debug)
 #  define eacsl_delete_block_debug export_alias(delete_block_debug)
@@ -304,23 +302,8 @@ void *eacsl_store_block(void *ptr, size_t size) {
 #endif
   bt_block *tmp = NULL;
   if (ptr) {
-    tmp = private_malloc(sizeof(bt_block));
-    tmp->ptr = (uintptr_t)ptr;
-    tmp->size = size;
-    tmp->init_ptr = NULL;
-    tmp->init_bytes = 0;
-    tmp->is_readonly = 0;
-    tmp->is_freeable = 0;
+    tmp = bt_alloc_block((uintptr_t)ptr, size);
     bt_insert(tmp);
-#ifdef E_ACSL_DEBUG
-    tmp->line = 0;
-    tmp->file = "undefined";
-#endif
-#ifdef E_ACSL_TEMPORAL
-    tmp->timestamp = NEW_TEMPORAL_TIMESTAMP();
-    tmp->temporal_shadow =
-        (size >= sizeof(void *)) ? private_malloc(size) : NULL;
-#endif
   }
   return tmp;
 }
@@ -355,12 +338,8 @@ void eacsl_delete_block(void *ptr) {
       private_abort("Attempt to delete untracked block\n");
 #endif
     if (tmp) {
-      bt_clean_block_init(tmp);
-#ifdef E_ACSL_TEMPORAL
-      private_free(tmp->temporal_shadow);
-#endif
       bt_remove(tmp);
-      private_free(tmp);
+      bt_free_block(tmp);
     }
   }
 }
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/e_acsl_observation_model.c b/src/plugins/e-acsl/share/e-acsl/observation_model/e_acsl_observation_model.c
index 59316ab4f16..c7a9fd1d2b2 100644
--- a/src/plugins/e-acsl/share/e-acsl/observation_model/e_acsl_observation_model.c
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/e_acsl_observation_model.c
@@ -93,6 +93,7 @@ int eacsl_separated(size_t count, ...) {
 /************************************************************************/
 
 #include "internals/e_acsl_heap_tracking.c"
+#include "internals/e_acsl_patricia_trie.c"
 #include "internals/e_acsl_safe_locations.c"
 
 /* Select memory model, either segment-based or bittree-based model should
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.c b/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.c
new file mode 100644
index 00000000000..d8c669d7f95
--- /dev/null
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.c
@@ -0,0 +1,503 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of the Frama-C's E-ACSL plug-in.                    */
+/*                                                                        */
+/*  Copyright (C) 2012-2021                                               */
+/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
+/*         alternatives)                                                  */
+/*                                                                        */
+/*  you can redistribute it and/or modify it under the terms of the GNU   */
+/*  Lesser General Public License as published by the Free Software       */
+/*  Foundation, version 2.1.                                              */
+/*                                                                        */
+/*  It is distributed in the hope that it will be useful,                 */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU Lesser General Public License for more details.                   */
+/*                                                                        */
+/*  See the GNU Lesser General Public License version 2.1                 */
+/*  for more details (enclosed in the file licenses/LGPLv2.1).            */
+/*                                                                        */
+/**************************************************************************/
+
+/*! ***********************************************************************
+ * \file
+ * \brief Patricia Trie API Implementation
+***************************************************************************/
+
+#include <stdint.h>
+
+#include "../../internals/e_acsl_config.h"
+#include "../../internals/e_acsl_malloc.h"
+#include "../../internals/e_acsl_private_assert.h"
+
+#include "e_acsl_patricia_trie.h"
+
+#if E_ACSL_OS_IS_LINUX
+#  define WORDBITS __WORDSIZE
+#elif E_ACSL_OS_IS_WINDOWS
+// On windows, __WORDSIZE is not available
+#  ifdef _WIN64
+#    define WORDBITS 64
+#  else
+#    define WORDBITS 32
+#  endif
+#else
+#  error "Unsupported OS"
+#endif
+
+#if WORDBITS == 16
+
+static const uintptr_t PT_MASKS[] = {
+    0x0,    0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
+    0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff};
+
+static const int PT_EQ[] = {0,  -1, 3,   -3, 6,   -5, 7,  -7, 12,
+                            -9, 11, -11, 14, -13, 15, 16, -16};
+static const int PT_NEQ[] = {0,  0, 1,   -2, 2,   -4, 5,   -6, 4,
+                             -8, 9, -10, 10, -12, 13, -14, -15};
+
+#elif WORDBITS == 32
+
+static const uintptr_t PT_MASKS[] = {
+    0x0,        0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
+    0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
+    0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
+    0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
+    0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
+    0xfffffffc, 0xfffffffe, 0xffffffff};
+
+static const int PT_EQ[] = {0,   -1,  3,   -3,  6,   -5,  7,   -7,  12,
+                            -9,  11,  -11, 14,  -13, 15,  -15, 24,  -17,
+                            19,  -19, 22,  -21, 23,  -23, 28,  -25, 27,
+                            -27, 30,  -29, 31,  32,  -32};
+
+static const int PT_NEQ[] = {0,   0,   1,   -2,  2,   -4,  5,   -6,  4,
+                             -8,  9,   -10, 10,  -12, 13,  -14, 8,   -16,
+                             17,  -18, 18,  -20, 21,  -22, 20,  -24, 25,
+                             -26, 26,  -28, 29,  -30, -31};
+
+#else /* WORDBITS == 64 */
+
+// clang-format off
+static const size_t PT_MASKS[] = {
+0x0,0x8000000000000000,0xc000000000000000,0xe000000000000000,0xf000000000000000,
+0xf800000000000000,0xfc00000000000000,0xfe00000000000000,0xff00000000000000,
+0xff80000000000000,0xffc0000000000000,0xffe0000000000000,0xfff0000000000000,
+0xfff8000000000000,0xfffc000000000000,0xfffe000000000000,0xffff000000000000,
+0xffff800000000000,0xffffc00000000000,0xffffe00000000000,0xfffff00000000000,
+0xfffff80000000000,0xfffffc0000000000,0xfffffe0000000000,0xffffff0000000000,
+0xffffff8000000000,0xffffffc000000000,0xffffffe000000000,0xfffffff000000000,
+0xfffffff800000000,0xfffffffc00000000,0xfffffffe00000000,0xffffffff00000000,
+0xffffffff80000000,0xffffffffc0000000,0xffffffffe0000000,0xfffffffff0000000,
+0xfffffffff8000000,0xfffffffffc000000,0xfffffffffe000000,0xffffffffff000000,
+0xffffffffff800000,0xffffffffffc00000,0xffffffffffe00000,0xfffffffffff00000,
+0xfffffffffff80000,0xfffffffffffc0000,0xfffffffffffe0000,0xffffffffffff0000,
+0xffffffffffff8000,0xffffffffffffc000,0xffffffffffffe000,0xfffffffffffff000,
+0xfffffffffffff800,0xfffffffffffffc00,0xfffffffffffffe00,0xffffffffffffff00,
+0xffffffffffffff80,0xffffffffffffffc0,0xffffffffffffffe0,0xfffffffffffffff0,
+0xfffffffffffffff8,0xfffffffffffffffc,0xfffffffffffffffe,0xffffffffffffffff};
+// clang-format on
+
+static const int PT_EQ[] = {
+    0,   -1,  3,   -3,  6,   -5,  7,   -7,  12,  -9,  11,  -11, 14,
+    -13, 15,  -15, 24,  -17, 19,  -19, 22,  -21, 23,  -23, 28,  -25,
+    27,  -27, 30,  -29, 31,  -31, 48,  -33, 35,  -35, 38,  -37, 39,
+    -39, 44,  -41, 43,  -43, 46,  -45, 47,  -47, 56,  -49, 51,  -51,
+    54,  -53, 55,  -55, 60,  -57, 59,  -59, 62,  -61, 63,  64,  -64};
+
+static const int PT_NEQ[] = {
+    0,   0,   1,   -2,  2,   -4,  5,   -6,  4,   -8,  9,   -10, 10,
+    -12, 13,  -14, 8,   -16, 17,  -18, 18,  -20, 21,  -22, 20,  -24,
+    25,  -26, 26,  -28, 29,  -30, 16,  -32, 33,  -34, 34,  -36, 37,
+    -38, 36,  -40, 41,  -42, 42,  -44, 45,  -46, 40,  -48, 49,  -50,
+    50,  -52, 53,  -54, 52,  -56, 57,  -58, 58,  -60, 61,  -62, -63};
+
+#endif
+
+typedef struct pt_node {
+  uintptr_t addr, mask;
+  struct pt_node *left, *right, *parent;
+  pt_leaf_t leaf;
+  int is_leaf;
+} pt_node_t;
+
+typedef struct pt_struct {
+  /*! \brief Root node of the trie. */
+  pt_node_t *root;
+  /*! \brief Function to extract the pointer of a leaf. */
+  get_ptr_fct_t get_ptr_fct;
+  /*! \brief Function to test if a leaf contains a pointer. */
+  contains_ptr_fct_t contains_ptr_fct;
+  /*! \brief Function to clean the content of a leaf. */
+  clean_leaf_fct_t clean_leaf_fct;
+  /*! \brief Function to print the content of a leaf. */
+  print_leaf_fct_t print_leaf_fct;
+} pt_struct_t;
+
+/* common prefix of two addresses */
+/*@ assigns \nothing;
+  @ ensures \forall int i;
+     0 <= i <= WORDBITS
+     ==> (PT_MASKS[i] & a) == (PT_MASKS[i] & b)
+     ==> \result >= PT_MASKS[i];
+  @ ensures (a & \result) == (b & \result);
+  @ ensures \exists int i; 0 <= i <= WORDBITS && \result == PT_MASKS[i];
+  @*/
+static uintptr_t pt_mask(uintptr_t a, uintptr_t b) {
+  uintptr_t nxor = ~(a ^ b), ret;
+  int i = WORDBITS / 2; /* dichotomic search, starting in the middle */
+
+  /* if the current mask matches we use transition from PT_EQ, else from PT_NEQ
+     we stop as soon as i is negative, meaning that we found the mask
+     a negative element i from PT_EQ or PT_NEQ means stop and return PT_MASKS[-i] */
+  /*@ loop invariant -WORDBITS <= i <= WORDBITS;
+    @ loop assigns i;
+    @*/
+  while (i > 0) {
+    //@ assert 0 < i <= WORDBITS;
+    //@ assert \valid(PT_MASKS+i);
+    if (nxor >= PT_MASKS[i])
+      //@ assert \valid(PT_EQ+i);
+      i = PT_EQ[i];
+    else
+      //@ assert \valid(PT_NEQ+i);
+      i = PT_NEQ[i];
+  }
+
+  //@ assert -WORDBITS <= i <= 0;
+  ret = PT_MASKS[-i];
+  DASSERT((a & ret) == (b & ret));
+  return ret;
+}
+
+pt_struct_t *pt_create(get_ptr_fct_t get_ptr_fct,
+                       contains_ptr_fct_t contains_ptr_fct,
+                       clean_leaf_fct_t clean_leaf_fct,
+                       print_leaf_fct_t print_leaf_fct) {
+  DASSERT(get_ptr_fct != NULL);
+  DASSERT(contains_ptr_fct != NULL);
+  DASSERT(clean_leaf_fct != NULL);
+  DASSERT(print_leaf_fct != NULL);
+
+  pt_struct_t *pt = private_malloc(sizeof(pt_struct_t));
+  DASSERT(pt != NULL);
+  pt->root = NULL;
+  pt->get_ptr_fct = get_ptr_fct;
+  pt->contains_ptr_fct = contains_ptr_fct;
+  pt->clean_leaf_fct = clean_leaf_fct;
+  pt->print_leaf_fct = print_leaf_fct;
+  return pt;
+}
+
+void pt_destroy(pt_struct_t *pt) {
+  DASSERT(pt != NULL);
+  pt_clean(pt);
+  private_free(pt);
+}
+
+/* called from pt_insert */
+/* the returned node will be the sibling of the soon to be added node */
+/*@ requires \valid_read(pt);
+  @ requires \valid_read(pt->root);
+  @ requires \valid_read(leaf);
+  @ assigns \nothing;
+  @ ensures \valid(\result); */
+static pt_node_t *pt_most_similar_node(const pt_struct_t *pt, pt_leaf_t leaf) {
+  DASSERT(pt != NULL);
+  DASSERT(pt->root != NULL);
+  DASSERT(leaf != NULL);
+  pt_node_t *curr = pt->root;
+  uintptr_t left_prefix, right_prefix;
+
+  uintptr_t ptr = (uintptr_t)pt->get_ptr_fct(leaf);
+
+  while (1) {
+    if (curr->is_leaf) {
+      return curr;
+    }
+    DASSERT(curr->left != NULL && curr->right != NULL);
+    left_prefix = pt_mask(curr->left->addr & curr->left->mask, ptr);
+    right_prefix = pt_mask(curr->right->addr & curr->right->mask, ptr);
+    if (left_prefix > right_prefix) {
+      curr = curr->left;
+    } else if (right_prefix > left_prefix) {
+      curr = curr->right;
+    } else {
+      return curr;
+    }
+  }
+}
+
+void pt_insert(pt_struct_t *pt, pt_leaf_t leaf) {
+  DASSERT(pt != NULL);
+  DASSERT(leaf != NULL);
+  pt_node_t *new_leaf_node;
+
+  uintptr_t ptr = (uintptr_t)pt->get_ptr_fct(leaf);
+
+  new_leaf_node = private_malloc(sizeof(pt_node_t));
+  DASSERT(new_leaf_node != NULL);
+  new_leaf_node->is_leaf = 1;
+  new_leaf_node->addr = ptr;
+  new_leaf_node->mask = PT_MASKS[WORDBITS]; /* ~0ul */
+  new_leaf_node->left = NULL;
+  new_leaf_node->right = NULL;
+  new_leaf_node->parent = NULL;
+  new_leaf_node->leaf = leaf;
+
+  if (pt->root == NULL) {
+    pt->root = new_leaf_node;
+  } else {
+    pt_node_t *sibling = pt_most_similar_node(pt, leaf), *parent, *aux;
+
+    DASSERT(sibling != NULL);
+    parent = private_malloc(sizeof(pt_node_t));
+    DASSERT(parent != NULL);
+    parent->is_leaf = 0;
+    parent->addr = sibling->addr & new_leaf_node->addr;
+    /*parent->mask = pt_mask(sibling->addr & sibling->mask, ptr);*/
+    parent->leaf = NULL;
+    if (new_leaf_node->addr <= sibling->addr) {
+      parent->left = new_leaf_node;
+      parent->right = sibling;
+    } else {
+      parent->left = sibling;
+      parent->right = new_leaf_node;
+    }
+    new_leaf_node->parent = parent;
+
+    if (sibling == pt->root) {
+      parent->parent = NULL;
+      parent->mask = pt_mask(sibling->addr & sibling->mask, ptr);
+      pt->root = parent;
+    } else {
+      if (sibling->parent->left == sibling) {
+        sibling->parent->left = parent;
+      } else {
+        sibling->parent->right = parent;
+      }
+      parent->parent = sibling->parent;
+
+      /* necessary ? -- begin */
+      aux = parent;
+      aux->mask = pt_mask(aux->left->addr & aux->left->mask,
+                          aux->right->addr & aux->right->mask);
+      /* necessary ? -- end */
+    }
+    sibling->parent = parent;
+    if (!sibling->is_leaf) {
+      sibling->mask = pt_mask(sibling->left->addr & sibling->left->mask,
+                              sibling->right->addr & sibling->right->mask);
+    }
+
+    DASSERT((parent->left == sibling && parent->right == new_leaf_node)
+            || (parent->left == new_leaf_node && parent->right == sibling));
+  }
+}
+
+/* called from pt_remove */
+/* the leaf we are looking for has to be in the tree */
+/*@ requires \valid_read(pt);
+  @ requires \valid_read(pt->root);
+  @ requires \valid_read(leaf);
+  @ assigns \nothing;
+  @ ensures \valid(\result);
+  @ ensures \result->leaf == ptr; */
+static pt_node_t *pt_get_leaf_node_from_leaf(const pt_struct_t *pt,
+                                             pt_leaf_t leaf) {
+  DASSERT(pt != NULL);
+  DASSERT(pt->root != NULL);
+  DASSERT(leaf != NULL);
+  pt_node_t *curr = pt->root;
+
+  uintptr_t ptr = (uintptr_t)pt->get_ptr_fct(leaf);
+
+  /*@ loop assigns curr; */
+  while (!curr->is_leaf) {
+    // the prefix is consistent
+    DASSERT((curr->addr & curr->mask) == (ptr & curr->mask));
+    // two children
+    DASSERT(curr->left != NULL && curr->right != NULL);
+    // the prefix of one child is consistent
+    if ((curr->right->addr & curr->right->mask) == (ptr & curr->right->mask)) {
+      curr = curr->right;
+    } else if ((curr->left->addr & curr->left->mask)
+               == (ptr & curr->left->mask)) {
+      curr = curr->left;
+    } else {
+      private_abort("Unreachable\n");
+    }
+  }
+  DASSERT(curr->is_leaf);
+  DASSERT(curr->leaf == leaf);
+  return curr;
+}
+
+void pt_remove(pt_struct_t *pt, pt_leaf_t leaf) {
+  pt_node_t *leaf_node_to_delete = pt_get_leaf_node_from_leaf(pt, leaf);
+  DASSERT(leaf_node_to_delete->leaf == leaf);
+
+  if (leaf_node_to_delete->parent == NULL) {
+    // the leaf is the root
+    pt->root = NULL;
+  } else {
+    pt_node_t *sibling, *parent;
+    parent = leaf_node_to_delete->parent;
+    sibling =
+        (leaf_node_to_delete == parent->left) ? parent->right : parent->left;
+    DASSERT(sibling != NULL);
+    // copying all sibling's fields into the parent's
+    parent->is_leaf = sibling->is_leaf;
+    parent->addr = sibling->addr;
+    parent->mask = sibling->mask;
+    parent->left = sibling->left;
+    parent->right = sibling->right;
+    parent->leaf = sibling->leaf;
+    if (!sibling->is_leaf) {
+      sibling->left->parent = parent;
+      sibling->right->parent = parent;
+    }
+    private_free(sibling);
+    /* necessary ? -- begin */
+    if (parent->parent != NULL) {
+      parent->parent->mask =
+          pt_mask(parent->parent->left->addr & parent->parent->left->mask,
+                  parent->parent->right->addr & parent->parent->right->mask);
+    }
+    /* necessary ? -- end */
+  }
+  private_free(leaf_node_to_delete);
+}
+
+pt_leaf_t pt_lookup(const pt_struct_t *pt, void *ptr) {
+  DASSERT(pt != NULL);
+  DASSERT(pt->root != NULL);
+  DASSERT(ptr != NULL);
+  pt_node_t *tmp = pt->root;
+
+  /*@ loop assigns tmp;
+    @*/
+  while (!tmp->is_leaf) {
+    // if the ptr we are looking for does not share the prefix of tmp
+    if ((tmp->addr & tmp->mask) != ((uintptr_t)ptr & tmp->mask)) {
+      return NULL;
+    }
+
+    // two children
+    DASSERT(tmp->left != NULL && tmp->right != NULL);
+    // the prefix of one child is consistent
+    if ((tmp->right->addr & tmp->right->mask)
+        == ((uintptr_t)ptr & tmp->right->mask)) {
+      tmp = tmp->right;
+    } else if ((tmp->left->addr & tmp->left->mask)
+               == ((uintptr_t)ptr & tmp->left->mask)) {
+      tmp = tmp->left;
+    } else {
+      return NULL;
+    }
+  }
+
+  if (pt->get_ptr_fct(tmp->leaf) != ptr) {
+    return NULL;
+  }
+  return tmp->leaf;
+}
+
+pt_leaf_t pt_find(const pt_struct_t *pt, void *ptr) {
+  DASSERT(pt != NULL);
+
+  if (pt->root == NULL || ptr == NULL) {
+    return NULL;
+  }
+
+  pt_node_t *tmp = pt->root;
+  pt_node_t *other_choice = NULL;
+
+  while (1) {
+    if (tmp->is_leaf) {
+      /* tmp cannot contain ptr because its begin addr is higher */
+      if (tmp->addr > (uintptr_t)ptr) {
+        return NULL;
+      }
+
+      /* tmp->addr <= ptr, tmp may contain ptr */
+      else if (pt->contains_ptr_fct(tmp->leaf, ptr)) {
+        return tmp->leaf;
+      }
+      /* tmp->addr <= ptr, but tmp does not contain ptr */
+      else {
+        return NULL;
+      }
+    }
+
+    DASSERT(tmp->left != NULL && tmp->right != NULL);
+
+    /* the right child has the highest address, so we test it first */
+    if ((tmp->right->addr & tmp->right->mask)
+        <= ((uintptr_t)ptr & tmp->right->mask)) {
+      other_choice = tmp->left;
+      tmp = tmp->right;
+    } else if ((tmp->left->addr & tmp->left->mask)
+               <= ((uintptr_t)ptr & tmp->left->mask)) {
+      tmp = tmp->left;
+    } else {
+      if (other_choice == NULL) {
+        return NULL;
+      } else {
+        tmp = other_choice;
+        other_choice = NULL;
+      }
+    }
+  }
+}
+
+static void pt_clean_rec(const pt_struct_t *pt, pt_node_t *ptr) {
+  if (ptr == NULL) {
+    return;
+  } else if (ptr->is_leaf) {
+    pt->clean_leaf_fct(ptr->leaf);
+    ptr->leaf = NULL;
+  } else {
+    pt_clean_rec(pt, ptr->left);
+    pt_clean_rec(pt, ptr->right);
+    ptr->left = ptr->right = NULL;
+  }
+  private_free(ptr);
+}
+
+void pt_clean(pt_struct_t *pt) {
+  DASSERT(pt != NULL);
+  pt_clean_rec(pt, pt->root);
+  pt->root = NULL;
+}
+
+#ifdef E_ACSL_DEBUG
+static void pt_print_node(const pt_struct_t *pt, pt_node_t *node, int depth) {
+  if (node == NULL) {
+    return;
+  }
+  // Indentation
+  for (int i = 0; i < depth; ++i) {
+    DLOG("  ");
+  }
+  // Print node
+  if (node->is_leaf) {
+    pt->print_leaf_fct(node->leaf);
+  } else {
+    DLOG("%p -- %p\n", (void *)node->mask, (void *)node->addr);
+    pt_print_node(pt, node->left, depth + 1);
+    pt_print_node(pt, node->right, depth + 1);
+  }
+}
+
+void pt_print(const pt_struct_t *pt) {
+  DLOG("------------DEBUG\n");
+  if (pt != NULL) {
+    pt_print_node(pt, pt->root, 0);
+  } else {
+    DLOG("Patricia trie is NULL\n");
+  }
+  DLOG("-----------------\n");
+}
+#endif // E_ACSL_DEBUG
diff --git a/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.h b/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.h
new file mode 100644
index 00000000000..ad237b701de
--- /dev/null
+++ b/src/plugins/e-acsl/share/e-acsl/observation_model/internals/e_acsl_patricia_trie.h
@@ -0,0 +1,148 @@
+/**************************************************************************/
+/*                                                                        */
+/*  This file is part of the Frama-C's E-ACSL plug-in.                    */
+/*                                                                        */
+/*  Copyright (C) 2012-2021                                               */
+/*    CEA (Commissariat à l'énergie atomique et aux énergies              */
+/*         alternatives)                                                  */
+/*                                                                        */
+/*  you can redistribute it and/or modify it under the terms of the GNU   */
+/*  Lesser General Public License as published by the Free Software       */
+/*  Foundation, version 2.1.                                              */
+/*                                                                        */
+/*  It is distributed in the hope that it will be useful,                 */
+/*  but WITHOUT ANY WARRANTY; without even the implied warranty of        */
+/*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
+/*  GNU Lesser General Public License for more details.                   */
+/*                                                                        */
+/*  See the GNU Lesser General Public License version 2.1                 */
+/*  for more details (enclosed in the file licenses/LGPLv2.1).            */
+/*                                                                        */
+/**************************************************************************/
+
+/*! ***********************************************************************
+ * \file
+ * \brief Patricia Trie API
+***************************************************************************/
+
+#ifndef E_ACSL_PATRICIA_TRIE
+#define E_ACSL_PATRICIA_TRIE
+
+#ifdef __FC_FEATURES_H
+#  include <__fc_alloc_axiomatic.h>
+#else
+/*@ ghost extern int __fc_heap_status; */
+#endif
+
+/*! \brief Opaque pointer representing a leaf on the patricia trie. */
+typedef void *pt_leaf_t;
+/*! \brief Function pointer to a function that retrieves the pointer of a
+    leaf. */
+typedef void *(*get_ptr_fct_t)(pt_leaf_t);
+/*! \brief Function pointer to a function that tests whether a leaf contains the
+    given pointer. */
+typedef int (*contains_ptr_fct_t)(pt_leaf_t, void *);
+/*! \brief Function pointer to a function that cleans (i.e. free memory) the
+    content of a leaf. */
+typedef void (*clean_leaf_fct_t)(pt_leaf_t);
+/*! \brief Function pointer to a function that prints the content of a leaf. */
+typedef void (*print_leaf_fct_t)(pt_leaf_t);
+
+/*! \brief Opaque structure of a patricia trie. */
+typedef struct pt_struct pt_struct_t;
+
+/*! \brief Create a patricia trie.
+    \param get_ptr_fct Function to extract the pointer of a leaf.
+    \param contains_ptr_fct Function to test if a leaf contains a pointer.
+    \param clean_leaf_fct Function to clean the content of a leaf.
+    \param print_leaf_fct Function to print the content of a leaf.
+    \return The newly created patricia trie. */
+/*@ requires \valid_function(get_ptr_fct_t get_ptr_fct);
+  @ requires \valid_function(contains_ptr_fct_t contains_ptr_fct);
+  @ requires \valid_function(clean_leaf_fct_t clean_leaf_fct);
+  @ requires \valid_function(print_leaf_fct_t print_leaf_fct);
+  @ allocates \result;
+  @ assigns *\result \from get_ptr_fct, contains_ptr_fct, clean_leaf_fct,
+                           print_leaf_fct;
+  @ admit ensures \valid(\result); */
+pt_struct_t *pt_create(get_ptr_fct_t get_ptr_fct,
+                       contains_ptr_fct_t contains_ptr_fct,
+                       clean_leaf_fct_t clean_leaf_fct,
+                       print_leaf_fct_t print_leaf_fct);
+
+/*! \brief Clean and destroy the patricia trie.
+    \param pt The patricia trie to destroy. */
+/*@ requires \valid(pt);
+  @ frees pt; */
+void pt_destroy(pt_struct_t *pt);
+
+/*! \brief Insert a new leaf to the patricia trie.
+    \param pt Patricia trie to update.
+    \param leaf Leaf to add to the trie. */
+/*@ requires \valid(pt);
+  @ assigns __fc_heap_status \from __fc_heap_status;
+  @ assigns *pt \from *pt, leaf, indirect:__fc_heap_status; */
+void pt_insert(pt_struct_t *pt, pt_leaf_t leaf);
+
+/*! \brief Remove an existing leaf from the patricia trie.
+    \param pt Patricia trie to update.
+    \param leaf Leaf to remove from the trie. */
+/*@ requires \valid(pt);
+  @ assigns __fc_heap_status \from __fc_heap_status;
+  @ assigns *pt \from *pt, leaf, indirect:__fc_heap_status; */
+void pt_remove(pt_struct_t *pt, pt_leaf_t leaf);
+
+/*! \brief Look for the leaf representing exactly the given pointer.
+
+    Given the function `get_fct_ptr` provided at the trie creation and a leaf
+    `l`, the leaf representing exactly the given pointer `ptr` is the leaf such
+    that `get_fct_ptr(l) == ptr`.
+
+    \param pt Patricia trie where to look for.
+    \param ptr Pointer to look for in the leaves of the patricia trie.
+    \return The leaf representing exactly the given pointer. */
+/*@ requires \valid_read(pt);
+  @ requires ptr != \null;
+  @ assigns \result \from *pt, indirect:ptr; */
+pt_leaf_t pt_lookup(const pt_struct_t *pt, void *ptr);
+
+/*! \brief Look for the leaf containing the given pointer.
+
+    Given the function `contains_ptr_fct` provided at the trie creation and a
+    leaf `l`, the leaf containing the given pointer is the leaf such that
+    `contains_ptr_fct(l, ptr) != 0`.
+
+    \param pt Patricia trie where to look for.
+    \param ptr Pointer to look for in the leaves of the patricia trie.
+    \return The leaf containing the given pointer. */
+/*@ requires \valid_read(pt);
+  @ assigns \result \from *pt, indirect:ptr; */
+pt_leaf_t pt_find(const pt_struct_t *pt, void *ptr);
+
+/*! \brief Clean the content of the given patricia trie.
+
+    Contrary to `pt_destroy()`, this function removes all leaves of the trie but
+    does not destroy the trie. The function `pt_insert()` can still be called on
+    the trie afterward.
+
+    \param pt Patricia trie to update. */
+/*@ requires \valid(pt);
+  @ assigns __fc_heap_status \from __fc_heap_status;
+  @ assigns *pt \from *pt, indirect:__fc_heap_status; */
+void pt_clean(pt_struct_t *pt);
+
+#ifdef E_ACSL_DEBUG
+
+/*! \brief Print the content of the given patricia trie.
+
+    The function `print_leaf_fct` provided at the trie creation is used to print
+    the leaves.
+
+    \param pt The patricia trie to print. */
+/*@ requires pt == \null || \valid_read(pt);
+  @ assigns \nothing; */
+void pt_print(const pt_struct_t *pt);
+
+#endif // E_ACSL_DEBUG
+
+#endif // E_ACSL_PATRICIA_TRIE
-- 
GitLab