[Groonga-commit] groonga/grnxx at bf332fd [master] Add grnxx::map::Patricia::reset/replace(), except for Bytes.

Back to archive index

susumu.yata null+****@clear*****
Thu Jun 27 12:49:57 JST 2013


susumu.yata	2013-06-27 12:49:57 +0900 (Thu, 27 Jun 2013)

  New Revision: bf332fd9c9842e03a139b51bfb42f89a84a0a8b5
  https://github.com/groonga/grnxx/commit/bf332fd9c9842e03a139b51bfb42f89a84a0a8b5

  Message:
    Add grnxx::map::Patricia::reset/replace(), except for Bytes.

  Modified files:
    lib/grnxx/map/patricia.cpp
    lib/grnxx/map/patricia.hpp

  Modified: lib/grnxx/map/patricia.cpp (+356 -177)
===================================================================
--- lib/grnxx/map/patricia.cpp    2013-06-27 10:50:35 +0900 (4f614e3)
+++ lib/grnxx/map/patricia.cpp    2013-06-27 12:49:57 +0900 (9a2233e)
@@ -131,6 +131,7 @@ bool Patricia<T>::unset(int64_t key_id) {
     // Not found or error.
     return false;
   }
+  // The root node must be a dead node because the above get() has succeeded.
   uint64_t node_id = ROOT_NODE_ID;
   Node *prev_node = nullptr;
   for ( ; ; ) {
@@ -139,74 +140,159 @@ bool Patricia<T>::unset(int64_t key_id) {
       // Error.
       return false;
     }
-    switch (node->status()) {
-      case NODE_DEAD: {
+    if (node->status() == NODE_LEAF) {
+      if (node->key_id() != key_id) {
         // Not found.
         return false;
       }
-      case NODE_LEAF: {
-        if (node->key_id() != key_id) {
-          // Not found.
-          return false;
-        }
-        keys_->unset(key_id);
-        if (prev_node) {
-          Node * const sibling_node = node + (node_id ^ 1) - node_id;
-          *prev_node = *sibling_node;
-        } else {
-          *node = Node::dead_node();
-        }
-        return true;
-      }
-      case NODE_BRANCH: {
-        node_id = node->offset() + get_ith_bit(key, node->bit_pos());
-        break;
+      keys_->unset(key_id);
+      if (prev_node) {
+        Node * const sibling_node = node + (node_id ^ 1) - node_id;
+        *prev_node = *sibling_node;
+      } else {
+        *node = Node::dead_node();
       }
+      return true;
     }
     prev_node = node;
+    node_id = node->offset() + get_ith_bit(key, node->bit_pos());
   }
 }
 
-//template <typename T>
-//bool Patricia<T>::reset(int64_t key_id, KeyArg dest_key) {
-//  // TODO
-//  return false;
-//}
-
 template <typename T>
-bool Patricia<T>::find(KeyArg key, int64_t *key_id) {
-  const Key normalized_key = Helper<T>::normalize(key);
+bool Patricia<T>::reset(int64_t key_id, KeyArg dest_key) {
+  // Find the source key.
+  Key src_key;
+  if (!get(key_id, &src_key)) {
+    // Not found or error.
+    return false;
+  }
+  // The root node must be a dead node because the above get() has succeeded.
   uint64_t node_id = ROOT_NODE_ID;
+  Node *src_node;
+  Node *src_prev_node = nullptr;
+  Node *src_sibling_node = nullptr;
   for ( ; ; ) {
-    Node node;
-    if (!nodes_->get(node_id, &node)) {
+    src_node = nodes_->get_pointer(node_id);
+    if (!src_node) {
       // Error.
       return false;
     }
-    switch (node.status()) {
-      case NODE_DEAD: {
+    if (src_node->status() == NODE_LEAF) {
+      if (src_node->key_id() != key_id) {
         // Not found.
         return false;
       }
-      case NODE_LEAF: {
-        Key stored_key;
-        if (!keys_->get_key(node.key_id(), &stored_key)) {
-          // Error.
-          return false;
-        }
-        if (!Helper<T>::equal_to(normalized_key, stored_key)) {
-          // Not found.
-          return false;
-        }
-        if (key_id) {
-          *key_id = node.key_id();
-        }
-        return true;
+      if (src_prev_node) {
+        src_sibling_node = src_node + (node_id ^ 1) - node_id;
       }
-      case NODE_BRANCH: {
-        node_id = node.offset() + get_ith_bit(normalized_key, node.bit_pos());
-        break;
+      break;
+    }
+    src_prev_node = src_node;
+    node_id = src_node->offset() + get_ith_bit(src_key, src_node->bit_pos());
+  }
+  // Add the destination key.
+  const Key dest_normalized_key = Helper<T>::normalize(dest_key);
+  node_id = ROOT_NODE_ID;
+  Node *history[(sizeof(Key) * 8) + 1];
+  int depth = -1;
+  for ( ; ; ) {
+    Node * const node = nodes_->get_pointer(node_id);
+    if (!node) {
+      // Error.
+      return false;
+    }
+    history[++depth] = node;
+    if (node->status() == NODE_LEAF) {
+      break;
+    }
+    node_id = node->offset() +
+              get_ith_bit(dest_normalized_key, node->bit_pos());
+  }
+  // Count the number of the common prefix bits.
+  Key stored_key;
+  if (!keys_->get_key(history[depth]->key_id(), &stored_key)) {
+    // Error.
+    return false;
+  }
+  const uint64_t count =
+      count_common_prefix_bits(dest_normalized_key, stored_key);
+  if (count == (sizeof(Key) * 8)) {
+    // Found.
+    return false;
+  }
+  // Find the branching point in "history".
+  while (depth > 0) {
+    if (history[depth - 1]->bit_pos() < count) {
+      break;
+    }
+    --depth;
+  }
+  Node * const dest_prev_node = history[depth];
+  Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
+  if (!next_nodes) {
+    return false;
+  }
+  if (!keys_->reset(key_id, dest_normalized_key)) {
+    // Error.
+    return false;
+  }
+  Node *dest_node;
+  Node *dest_sibling_node;
+  if (get_ith_bit(dest_normalized_key, count)) {
+    dest_node = &next_nodes[1];
+    dest_sibling_node = &next_nodes[0];
+  } else {
+    dest_node = &next_nodes[0];
+    dest_sibling_node = &next_nodes[1];
+  }
+  if (dest_prev_node == src_prev_node) {
+    src_prev_node = dest_sibling_node;
+  } else if (dest_prev_node == src_node) {
+    src_sibling_node = dest_node;
+    src_prev_node = dest_prev_node;
+  }
+  *dest_sibling_node = *dest_prev_node;
+  *dest_node = Node::leaf_node(key_id);
+  *dest_prev_node = Node::branch_node(count, header_->next_node_id);
+  *src_prev_node = *src_sibling_node;
+  header_->next_node_id += 2;
+  return true;
+}
+
+template <typename T>
+bool Patricia<T>::find(KeyArg key, int64_t *key_id) {
+  const Key normalized_key = Helper<T>::normalize(key);
+  uint64_t node_id = ROOT_NODE_ID;
+  Node node;
+  if (!nodes_->get(node_id, &node)) {
+    // Error.
+    return false;
+  }
+  if (node.status() == NODE_DEAD) {
+    // Not found.
+    return false;
+  }
+  for ( ; ; ) {
+    if (node.status() == NODE_LEAF) {
+      Key stored_key;
+      if (!keys_->get_key(node.key_id(), &stored_key)) {
+        // Error.
+        return false;
+      }
+      if (!Helper<T>::equal_to(normalized_key, stored_key)) {
+        // Not found.
+        return false;
       }
+      if (key_id) {
+        *key_id = node.key_id();
+      }
+      return true;
+    }
+    node_id = node.offset() + get_ith_bit(normalized_key, node.bit_pos());
+    if (!nodes_->get(node_id, &node)) {
+      // Error.
+      return false;
     }
   }
 }
@@ -295,52 +381,160 @@ template <typename T>
 bool Patricia<T>::remove(KeyArg key) {
   const Key normalized_key = Helper<T>::normalize(key);
   uint64_t node_id = ROOT_NODE_ID;
-  Node * prev_node = nullptr;
+  Node *node = nodes_->get_pointer(node_id);
+  if (!node) {
+    // Error.
+    return false;
+  }
+  if (node->status() == NODE_DEAD) {
+    // Not found.
+    return false;
+  }
+  Node *prev_node = nullptr;
   for ( ; ; ) {
-    Node * const node = nodes_->get_pointer(node_id);
+    if (node->status() == NODE_LEAF) {
+      Key stored_key;
+      if (!keys_->get_key(node->key_id(), &stored_key)) {
+        // Error.
+        return false;
+      }
+      if (!Helper<T>::equal_to(normalized_key, stored_key)) {
+        // Not found.
+        return false;
+      }
+      keys_->unset(node->key_id());
+      if (prev_node) {
+        Node * const sibling_node = node + (node_id ^ 1) - node_id;
+        *prev_node = *sibling_node;
+      } else {
+        *node = Node::dead_node();
+      }
+      return true;
+    }
+    prev_node = node;
+    node_id = node->offset() + get_ith_bit(normalized_key, node->bit_pos());
+    node = nodes_->get_pointer(node_id);
     if (!node) {
       // Error.
       return false;
     }
-    switch (node->status()) {
-      case NODE_DEAD: {
-        // Not found.
+  }
+}
+
+template <typename T>
+bool Patricia<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) {
+  const Key src_normalized_key = Helper<T>::normalize(src_key);
+  uint64_t node_id = ROOT_NODE_ID;
+  Node *src_node = nodes_->get_pointer(node_id);
+  if (!src_node) {
+    // Error.
+    return false;
+  }
+  if (src_node->status() == NODE_DEAD) {
+    // Not found.
+    return false;
+  }
+  int64_t src_key_id;
+  Node *src_prev_node = nullptr;
+  Node *src_sibling_node = nullptr;
+  for ( ; ; ) {
+    if (src_node->status() == NODE_LEAF) {
+      src_key_id = src_node->key_id();
+      Key stored_key;
+      if (!keys_->get_key(src_key_id, &stored_key)) {
+        // Error.
         return false;
       }
-      case NODE_LEAF: {
-        Key stored_key;
-        if (!keys_->get_key(node->key_id(), &stored_key)) {
-          // Error.
-          return false;
-        }
-        if (!Helper<T>::equal_to(normalized_key, stored_key)) {
-          // Not found.
-          return false;
-        }
-        keys_->unset(node->key_id());
-        if (prev_node) {
-          Node * const sibling_node = node + (node_id ^ 1) - node_id;
-          *prev_node = *sibling_node;
-        } else {
-          *node = Node::dead_node();
-        }
-        return true;
+      if (!Helper<T>::equal_to(src_normalized_key, stored_key)) {
+        // Not found.
+        return false;
       }
-      case NODE_BRANCH: {
-        node_id = node->offset() + get_ith_bit(normalized_key, node->bit_pos());
-        break;
+      if (src_prev_node) {
+        src_sibling_node = src_node + (node_id ^ 1) - node_id;
       }
+      break;
+    }
+    src_prev_node = src_node;
+    node_id = src_node->offset() +
+              get_ith_bit(src_normalized_key, src_node->bit_pos());
+    src_node = nodes_->get_pointer(node_id);
+    if (!src_node) {
+      // Error.
+      return false;
     }
-    prev_node = node;
   }
+  // Add the destination key.
+  const Key dest_normalized_key = Helper<T>::normalize(dest_key);
+  node_id = ROOT_NODE_ID;
+  Node *history[(sizeof(Key) * 8) + 1];
+  int depth = -1;
+  for ( ; ; ) {
+    Node * const node = nodes_->get_pointer(node_id);
+    if (!node) {
+      // Error.
+      return false;
+    }
+    history[++depth] = node;
+    if (node->status() == NODE_LEAF) {
+      break;
+    }
+    node_id = node->offset() +
+              get_ith_bit(dest_normalized_key, node->bit_pos());
+  }
+  // Count the number of the common prefix bits.
+  Key stored_key;
+  if (!keys_->get_key(history[depth]->key_id(), &stored_key)) {
+    // Error.
+    return false;
+  }
+  const uint64_t count =
+      count_common_prefix_bits(dest_normalized_key, stored_key);
+  if (count == (sizeof(Key) * 8)) {
+    // Found.
+    return false;
+  }
+  // Find the branching point in "history".
+  while (depth > 0) {
+    if (history[depth - 1]->bit_pos() < count) {
+      break;
+    }
+    --depth;
+  }
+  Node * const dest_prev_node = history[depth];
+  Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
+  if (!next_nodes) {
+    return false;
+  }
+  if (!keys_->reset(src_key_id, dest_normalized_key)) {
+    // Error.
+    return false;
+  }
+  Node *dest_node;
+  Node *dest_sibling_node;
+  if (get_ith_bit(dest_normalized_key, count)) {
+    dest_node = &next_nodes[1];
+    dest_sibling_node = &next_nodes[0];
+  } else {
+    dest_node = &next_nodes[0];
+    dest_sibling_node = &next_nodes[1];
+  }
+  if (dest_prev_node == src_prev_node) {
+    src_prev_node = dest_sibling_node;
+  } else if (dest_prev_node == src_node) {
+    src_sibling_node = dest_node;
+    src_prev_node = dest_prev_node;
+  }
+  *dest_sibling_node = *dest_prev_node;
+  *dest_node = Node::leaf_node(src_key_id);
+  *dest_prev_node = Node::branch_node(count, header_->next_node_id);
+  *src_prev_node = *src_sibling_node;
+  header_->next_node_id += 2;
+  if (key_id) {
+    *key_id = src_key_id;
+  }
+  return true;
 }
 
-//template <typename T>
-//bool Patricia<T>::replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id) {
-//  // TODO
-//  return false;
-//}
-
 template <typename T>
 bool Patricia<T>::truncate() {
   Node * const root_node = nodes_->get_pointer(ROOT_NODE_ID);
@@ -650,19 +844,18 @@ bool Patricia<Bytes>::find(KeyArg key, int64_t *key_id) {
 }
 
 bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) {
+  int64_t * const cache = nullptr;
 //  int64_t * const cache =
 //      cache_->get_pointer(hash_table::Hash<Key>()(key) % cache_->size());
-//  {
-//    if ((*cache >= 0) && (*cache < keys_->max_key_id())) {
-//      bool bit;
-//      if (keys_->get_bit(*cache, &bit) && bit) {
-//        Key cached_key;
-//        if (keys_->get_key(*cache, &cached_key) && (key == cached_key)) {
-//          if (key_id) {
-//            *key_id = *cache;
-//          }
-//          return false;
+//  if ((*cache >= 0) && (*cache < keys_->max_key_id())) {
+//    bool bit;
+//    if (keys_->get_bit(*cache, &bit) && bit) {
+//      Key cached_key;
+//      if (keys_->get_key(*cache, &cached_key) && (key == cached_key)) {
+//        if (key_id) {
+//          *key_id = *cache;
 //        }
+//        return false;
 //      }
 //    }
 //  }
@@ -683,9 +876,9 @@ bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) {
     if (key_id) {
       *key_id = next_key_id;
     }
-//    if (cache) {
-//      *cache = next_key_id;
-//    }
+    if (cache) {
+      *cache = next_key_id;
+    }
     return true;
   }
   const uint64_t bit_size = key.size() * 8;
@@ -740,40 +933,13 @@ bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) {
       if (key_id) {
         *key_id = node->key_id();
       }
-//      if (cache) {
-//        *cache = node->key_id();
-//      }
+      if (cache) {
+        *cache = node->key_id();
+      }
       return false;
     }
     node = history[depth % 8];
-    Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
-    if (!next_nodes) {
-      return false;
-    }
-    int64_t next_key_id;
-    if (!keys_->add(key, &next_key_id)) {
-      // Error.
-      return false;
-    }
-    if (count == key.size()) {
-      // "key" is a prefix of "stored_key".
-      next_nodes[0] = Node::leaf_node(next_key_id);
-      next_nodes[1] = *node;
-      *node = Node::terminal_node(count * 8, header_->next_node_id);
-    } else {
-      // "stored_key" is a prefix of "key".
-      next_nodes[0] = *node;
-      next_nodes[1] = Node::leaf_node(next_key_id);
-      *node = Node::terminal_node(count * 8, header_->next_node_id);
-    }
-    header_->next_node_id += 2;
-    if (key_id) {
-      *key_id = next_key_id;
-    }
-//    if (cache) {
-//      *cache = next_key_id;
-//    }
-    return true;
+    return add_key_with_terminal_node(node, key, count, key_id, cache);
   }
   count = (count * 8) + 7 - bit_scan_reverse(key[count] ^ stored_key[count]);
   // Find the branching point in "history".
@@ -791,31 +957,7 @@ bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) {
   if (depth >= min_depth) {
     // The branching point exists in "history".
     node = history[(depth + 1) % 8];
-    Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
-    if (!next_nodes) {
-      return false;
-    }
-    int64_t next_key_id;
-    if (!keys_->add(key, &next_key_id)) {
-      // Error.
-      return false;
-    }
-    if (get_ith_bit(key, count)) {
-      next_nodes[0] = *node;
-      next_nodes[1] = Node::leaf_node(next_key_id);
-    } else {
-      next_nodes[0] = Node::leaf_node(next_key_id);
-      next_nodes[1] = *node;
-    }
-    *node = Node::branch_node(count, header_->next_node_id);
-    header_->next_node_id += 2;
-    if (key_id) {
-      *key_id = next_key_id;
-    }
-//    if (cache) {
-//      *cache = next_key_id;
-//    }
-    return true;
+    return add_key_with_branch_node(node, key, count, key_id, cache);
   }
   // Find the branching point with the naive method.
   node_id = ROOT_NODE_ID;
@@ -839,33 +981,7 @@ bool Patricia<Bytes>::add(KeyArg key, int64_t *key_id) {
       node_id = node->offset() + 1;
     }
   }
-  Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
-  if (!next_nodes) {
-    // Error.
-    return false;
-  }
-  int64_t next_key_id;
-  if (!keys_->add(key, &next_key_id)) {
-    // Error.
-    return false;
-  }
-  // Create a branch node.
-  if (get_ith_bit(key, count)) {
-    next_nodes[0] = *node;
-    next_nodes[1] = Node::leaf_node(next_key_id);
-  } else {
-    next_nodes[0] = Node::leaf_node(next_key_id);
-    next_nodes[1] = *node;
-  }
-  *node = Node::branch_node(count, header_->next_node_id);
-  header_->next_node_id += 2;
-  if (key_id) {
-    *key_id = next_key_id;
-  }
-//  if (cache) {
-//    *cache = next_key_id;
-//  }
-  return true;
+  return add_key_with_branch_node(node, key, count, key_id, cache);
 }
 
 bool Patricia<Bytes>::remove(KeyArg key) {
@@ -1065,6 +1181,69 @@ bool Patricia<Bytes>::open_map(Storage *storage, uint32_t storage_node_id) {
   return true;
 }
 
+bool Patricia<Bytes>::add_key_with_terminal_node(
+    Node *node, KeyArg key, uint64_t count,
+    int64_t *key_id, int64_t *cache) {
+  Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
+  if (!next_nodes) {
+    return false;
+  }
+  int64_t next_key_id;
+  if (!keys_->add(key, &next_key_id)) {
+    // Error.
+    return false;
+  }
+  if (count == key.size()) {
+    // "key" is a prefix of "stored_key".
+    next_nodes[0] = Node::leaf_node(next_key_id);
+    next_nodes[1] = *node;
+    *node = Node::terminal_node(count * 8, header_->next_node_id);
+  } else {
+    // "stored_key" is a prefix of "key".
+    next_nodes[0] = *node;
+    next_nodes[1] = Node::leaf_node(next_key_id);
+    *node = Node::terminal_node(count * 8, header_->next_node_id);
+  }
+  header_->next_node_id += 2;
+  if (key_id) {
+    *key_id = next_key_id;
+  }
+  if (cache) {
+    *cache = next_key_id;
+  }
+  return true;
+}
+
+bool Patricia<Bytes>::add_key_with_branch_node(
+    Node *node, KeyArg key, uint64_t bit_pos,
+    int64_t *key_id, int64_t *cache) {
+  Node * const next_nodes = nodes_->get_pointer(header_->next_node_id);
+  if (!next_nodes) {
+    return false;
+  }
+  int64_t next_key_id;
+  if (!keys_->add(key, &next_key_id)) {
+    // Error.
+    return false;
+  }
+  if (get_ith_bit(key, bit_pos)) {
+    next_nodes[0] = *node;
+    next_nodes[1] = Node::leaf_node(next_key_id);
+  } else {
+    next_nodes[0] = Node::leaf_node(next_key_id);
+    next_nodes[1] = *node;
+  }
+  *node = Node::branch_node(bit_pos, header_->next_node_id);
+  header_->next_node_id += 2;
+  if (key_id) {
+    *key_id = next_key_id;
+  }
+  if (cache) {
+    *cache = next_key_id;
+  }
+  return true;
+}
+
 uint64_t Patricia<Bytes>::get_ith_bit(KeyArg key, uint64_t bit_pos) {
   return (key[bit_pos / 8] >> (7 - (bit_pos % 8))) & 1;
 }

  Modified: lib/grnxx/map/patricia.hpp (+7 -2)
===================================================================
--- lib/grnxx/map/patricia.hpp    2013-06-27 10:50:35 +0900 (2ca3b16)
+++ lib/grnxx/map/patricia.hpp    2013-06-27 12:49:57 +0900 (28933bb)
@@ -66,12 +66,12 @@ class Patricia : public Map<T> {
 
   bool get(int64_t key_id, Key *key = nullptr);
   bool unset(int64_t key_id);
-//  bool reset(int64_t key_id, KeyArg dest_key);
+  bool reset(int64_t key_id, KeyArg dest_key);
 
   bool find(KeyArg key, int64_t *key_id = nullptr);
   bool add(KeyArg key, int64_t *key_id = nullptr);
   bool remove(KeyArg key);
-//  bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr);
+  bool replace(KeyArg src_key, KeyArg dest_key, int64_t *key_id = nullptr);
 
   bool truncate();
 
@@ -141,6 +141,11 @@ class Patricia<Bytes> : public Map<Bytes> {
                   const MapOptions &options);
   bool open_map(Storage *storage, uint32_t storage_node_id);
 
+  bool add_key_with_terminal_node(Node *node, KeyArg key, uint64_t count,
+                                  int64_t *key_id, int64_t *cache);
+  bool add_key_with_branch_node(Node *node, KeyArg key, uint64_t bit_pos,
+                                int64_t *key_id, int64_t *cache);
+
   static uint64_t get_ith_bit(KeyArg key, uint64_t bit_pos);
 };
 
-------------- next part --------------
HTML����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index