|
| 1 | +;; |
| 2 | +;; Copyright (c) Huahai Yang. All rights reserved. |
| 3 | +;; The use and distribution terms for this software are covered by the |
| 4 | +;; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) |
| 5 | +;; which can be found in the file LICENSE at the root of this distribution. |
| 6 | +;; By using this software in any fashion, you are agreeing to be bound by |
| 7 | +;; the terms of this license. |
| 8 | +;; You must not remove this notice, or any other, from this software. |
| 9 | +;; |
| 10 | + |
| 11 | +(ns editscript.util.index |
| 12 | + (:require [editscript.edit :as e] |
| 13 | + #?(:cljs [goog.math.Long :refer [getMaxValue]])) |
| 14 | + #?(:clj (:import [clojure.lang PersistentVector] |
| 15 | + [java.io Writer])) ) |
| 16 | + |
| 17 | +;; indexing |
| 18 | + |
| 19 | +(defprotocol INode |
| 20 | + (get-path [this] "Get the path to the node from root") |
| 21 | + (get-value [this] "Get the actual data") |
| 22 | + (get-children [this] "Get all children node in a map") |
| 23 | + (add-child [this node] "Add a child node") |
| 24 | + (get-key [this] "Get the key of this node") |
| 25 | + (get-parent [this] "Get the parent node") |
| 26 | + (get-first [this] "Get the first child node") |
| 27 | + (get-last [this] "Get the last child node") |
| 28 | + (get-next [this] "Get the next sibling node") |
| 29 | + (set-next [this node] "Set the next sibling node") |
| 30 | + (set-order [this o] "Set the traversal order of this node") |
| 31 | + (get-order [this] "Get the order of this node in traversal") |
| 32 | + (get-size [this] "Get the size of sub-tree, used to estimate cost") |
| 33 | + (set-size [this s] "Set the size of sub-tree")) |
| 34 | + |
| 35 | +(deftype Node [^PersistentVector path |
| 36 | + value |
| 37 | + parent |
| 38 | + ^:unsynchronized-mutable children |
| 39 | + ^:unsynchronized-mutable first |
| 40 | + ^:unsynchronized-mutable last |
| 41 | + ^:unsynchronized-mutable next |
| 42 | + ^:unsynchronized-mutable index |
| 43 | + ^:unsynchronized-mutable ^long order |
| 44 | + ^:unsynchronized-mutable ^long size] |
| 45 | + INode |
| 46 | + (get-path [_] path) |
| 47 | + (get-key [this] (-> this get-path peek)) |
| 48 | + (get-value [_] value) |
| 49 | + (get-parent [_] parent) |
| 50 | + (get-children [_] children) |
| 51 | + (get-first [_] first) |
| 52 | + (get-last [_] last) |
| 53 | + (get-next [_] next) |
| 54 | + (set-next [_ n] (set! next n)) |
| 55 | + (get-order [_] order) |
| 56 | + (set-order [this o] (set! order (long o)) this) |
| 57 | + (get-size [_] size) |
| 58 | + (set-size [this s] (set! size (long s)) this) |
| 59 | + (add-child [_ node] |
| 60 | + (set! children (assoc children (get-key node) node)) |
| 61 | + (when last (set-next last node)) |
| 62 | + (when-not first (set! first node)) |
| 63 | + (set! last node) |
| 64 | + node)) |
| 65 | + |
| 66 | +#?(:clj |
| 67 | + (defmethod print-method Node |
| 68 | + [x ^Writer writer] |
| 69 | + (print-method {:value (get-value x) |
| 70 | + :order (get-order x) |
| 71 | + :children (get-children x)} |
| 72 | + writer))) |
| 73 | + |
| 74 | +(declare index*) |
| 75 | + |
| 76 | +(defn- associative-children |
| 77 | + "map and vector are associative" |
| 78 | + [order path data parent] |
| 79 | + (reduce-kv |
| 80 | + (fn [_ k v] |
| 81 | + (index* order (conj path k) v parent)) |
| 82 | + nil |
| 83 | + data)) |
| 84 | + |
| 85 | +(defn- set-children |
| 86 | + "set is a map of keys to themselves" |
| 87 | + [order path data parent] |
| 88 | + (doseq [x data] |
| 89 | + (index* order (conj path x) x parent))) |
| 90 | + |
| 91 | +(defn- list-children |
| 92 | + "add index as key" |
| 93 | + [order path data parent] |
| 94 | + (reduce |
| 95 | + (fn [i x] |
| 96 | + (index* order (conj path i) x parent) |
| 97 | + (inc ^long i)) |
| 98 | + 0 |
| 99 | + data)) |
| 100 | + |
| 101 | +(defn- inc-order |
| 102 | + "order value reflects the size of elements" |
| 103 | + [order ^long size] |
| 104 | + (vswap! order (fn [o] (+ size ^long o)))) |
| 105 | + |
| 106 | +(defn- index-collection |
| 107 | + [type order path data parent] |
| 108 | + (let [node (->Node path data parent {} nil nil nil 0 0 1)] |
| 109 | + (add-child parent node) |
| 110 | + (case type |
| 111 | + (:map :vec) (associative-children order path data node) |
| 112 | + :set (set-children order path data node) |
| 113 | + :lst (list-children order path data node)) |
| 114 | + (let [^long cs (->> (get-children node) vals (map get-size) (reduce +)) |
| 115 | + size (+ (long (get-size node)) cs)] |
| 116 | + (doto node |
| 117 | + (set-order @order) |
| 118 | + (set-size size)) |
| 119 | + (inc-order order size)) |
| 120 | + node)) |
| 121 | + |
| 122 | +(defn- index-value |
| 123 | + [order path data parent] |
| 124 | + (let [node (->Node path data parent nil nil nil nil 0 @order 1)] |
| 125 | + (add-child parent node) |
| 126 | + (inc-order order 1) |
| 127 | + node)) |
| 128 | + |
| 129 | +(defn- index* |
| 130 | + [order path data parent] |
| 131 | + (let [type (e/get-type data)] |
| 132 | + (if (or (= type :val) (= type :str)) |
| 133 | + (index-value order path data parent) |
| 134 | + (index-collection type order path data parent)))) |
| 135 | + |
| 136 | +(defn index |
| 137 | + "Traverse data to build an indexing tree of Nodes, |
| 138 | + compute path, sizes of sub-trees, siblings, etc. for each Node. |
| 139 | + This takes little time" |
| 140 | + [data] |
| 141 | + (let [order (volatile! 0)] |
| 142 | + (index* order [] data (->Node [] ::dummy nil {} nil nil nil 0 -1 0)))) |
0 commit comments