diff --git a/book.iml b/book.iml index 32c73e0..a61edf0 100644 --- a/book.iml +++ b/book.iml @@ -17,8 +17,16 @@ + + + + + + + + \ No newline at end of file diff --git a/project.clj b/project.clj index ca08dd6..7c979d4 100644 --- a/project.clj +++ b/project.clj @@ -3,7 +3,8 @@ :url "http://example.com/FIXME" :license {:name "Eclipse Public License" :url "http://www.eclipse.org/legal/epl-v10.html"} - :dependencies [[org.clojure/clojure "1.9.0"]] + :dependencies [[org.clojure/clojure "1.9.0"] + [org.clojure/core.async "0.4.474"]] :java-source-paths ["src/java"] :main ^:skip-aot book.core :target-path "target/%s" diff --git a/src/book/core.clj b/src/book/core.clj index 010c43e..2090939 100644 --- a/src/book/core.clj +++ b/src/book/core.clj @@ -1,5 +1,80 @@ -(ns book.core) +(ns book.core + (:require [book.match :refer [sell? + create-buy-book + create-sell-book + match-order-in-book]] + [book.util :refer :all] + [book.order] ;; for spec side effect + [clojure.edn :as edn] + [clojure.core.async :refer [chan go >!! !! trades-channel trades)) + (when leftover-order (>!! new-book-order-channel leftover-order)) + (recur (!! trades-channel trades)) + (when leftover-order (>!! new-book-order-channel leftover-order)) + (recur ( " trades-channel)) + (go (print-chan "order > " new-book-order-channel)) + (go (process-orders master-book incoming-order-channel trades-channel new-book-order-channel)) + (loop [order (read-order)] + (if (some? order) + (do + (let [order-with-id (add-id-to-order order)] + (>!! incoming-order-channel order-with-id) + (println "\n\norder accepted with id: " (:book.order/id order-with-id)))) + + (println "invalid order")) + (recur (read-order)))) diff --git a/src/book/match.clj b/src/book/match.clj index 5598b78..699c414 100644 --- a/src/book/match.clj +++ b/src/book/match.clj @@ -1,17 +1,9 @@ (ns book.match - (:import [book.PersistentSortedList]) - (:require [book.order] + (:require [book.util :refer [sorted-list-by]] [clojure.spec.alpha :as s] - [clojure.edn :as edn]) - (:gen-class)) + [clojure.edn :as edn])) -(defn sorted-list [& keys] - (book.PersistentSortedList/create (seq keys))) - -(defn sorted-list-by [comparator & keys] - (book.PersistentSortedList/create comparator (seq keys))) - ;; Let say a book is two collections. The first called ;; sell-book contains all the sell orders. The second @@ -95,9 +87,9 @@ (when (pos? leftover-quantity) (assoc order :quantity leftover-quantity)))) -(defn match-order-in-book [sell-book order] - (let [trades (create-trades order sell-book) - new-book (compute-new-book-after-trades sell-book trades) +(defn match-order-in-book [book order] + (let [trades (create-trades order book) + new-book (compute-new-book-after-trades book trades) new-buy-order (leftover-order order trades)] [trades new-book new-buy-order])) @@ -112,7 +104,7 @@ ; ;(defn -main ; [& args] -; (let [order (-> args first edn/read-string)] +; (let [order (-> a+rgs first edn/read-string)] ; (if (not (s/valid? :book.order/order order)) ; (println "invalid order :( ") ; (println (place-order book order))))) diff --git a/src/book/util.clj b/src/book/util.clj new file mode 100644 index 0000000..de87dd7 --- /dev/null +++ b/src/book/util.clj @@ -0,0 +1,9 @@ +(ns book.util + (:import [book.PersistentSortedList])) + +(defn sorted-list [& keys] + (book.PersistentSortedList/create (seq keys))) + +(defn sorted-list-by [comparator & keys] + (book.PersistentSortedList/create comparator (seq keys))) + diff --git a/src/java/book/PersistentSortedList.java b/src/java/book/PersistentSortedList.java index e52f1e8..6ec5220 100644 --- a/src/java/book/PersistentSortedList.java +++ b/src/java/book/PersistentSortedList.java @@ -3,10 +3,18 @@ package book; import clojure.lang.*; import java.util.*; -public class PersistentSortedList extends ASeq implements IPersistentList, IReduce, List, Counted{ +//IPersistentVector, Iterable, +// List, +// RandomAccess, Comparable, +// Serializable, IHashEq + +public class PersistentSortedList extends Obj implements Iterable, RandomAccess, Comparable, + IHashEq, IPersistentList, IReduce, ISeq, + List, Counted{ final private PersistentTreeMap impl; final private int _count; static public final PersistentSortedList EMPTY = new PersistentSortedList(null, PersistentTreeMap.EMPTY, 0); + private int _hasheq = 0; public static PersistentSortedList create(ISeq items){ PersistentSortedList ret = EMPTY; @@ -42,6 +50,24 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu return new PersistentSortedList(meta(), impl.assoc(o, newList), _count + 1); } + @Override + public IPersistentCollection empty() { + return PersistentSortedList.EMPTY; + } + + @Override + public boolean equiv(Object obj) { + if(!(obj instanceof Sequential || obj instanceof List)) + return false; + ISeq ms = RT.seq(obj); + for(ISeq s = seq(); s != null; s = s.next(), ms = ms.next()){ + if(ms == null || !Util.equiv(s.first(), ms.first())){ + return false; + } + } + return ms == null; + } + @Override public Object peek() { if(_count == 0){ @@ -70,7 +96,7 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu @Override public Object reduce(IFn f) { Object ret = first(); - for(ISeq s = next(); s != null; s = s.next()) { + for(ISeq s = (ISeq) next(); s != null; s = s.next()) { ret = f.invoke(ret, s.first()); if (RT.isReduced(ret)) return ((IDeref)ret).deref(); } @@ -80,7 +106,7 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu @Override public Object reduce(IFn f, Object start) { Object ret = f.invoke(start, first()); - for(ISeq s = next(); s != null; s = s.next()) { + for(PersistentSortedList s = next(); s != null; s = s.next()) { if (RT.isReduced(ret)) return ((IDeref)ret).deref(); ret = f.invoke(ret, s.first()); } @@ -88,12 +114,10 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu return ret; } - @Override public Object first() { return peek(); } - @Override public PersistentSortedList next() { if(_count == 0){ return null; @@ -109,6 +133,18 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu return new PersistentSortedList(meta(), nextImpl, _count - 1); } + // Things that i did not want to implement. + + private List reify(){ + return Collections.unmodifiableList(new ArrayList(this)); + } + + @Override + public ISeq more() { + ISeq s = next(); + return s == null ? PersistentSortedList.EMPTY : s; + } + @Override public Obj withMeta(IPersistentMap meta) { if(meta != meta()){ @@ -116,5 +152,151 @@ public class PersistentSortedList extends ASeq implements IPersistentList, IRedu } return this; } + + @Override + public int hasheq() { + if(_hasheq == 0){ + _hasheq = Murmur3.hashOrdered(this); + } + return _hasheq; + } + + @Override + public ISeq seq() { + return count() == 0 ? null : (ISeq) this; + } + + @Override + public int compareTo(Object o) { + return 0; + } + + @Override + public int size() { + return count(); + } + + @Override + public boolean isEmpty() { + return seq() == null; + } + + @Override + public boolean contains(Object o) { + return impl.containsKey(o); + } + + @Override + public Object[] toArray() { + return RT.seqToArray(seq()); + } + + @Override + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean addAll(int i, Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public void clear() { + throw new UnsupportedOperationException(); + } + + @Override + public Object get(int index) { + return RT.nth(this, index); + } + + @Override + public Object set(int i, Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public void add(int i, Object o) { + throw new UnsupportedOperationException(); + } + + @Override + public Object remove(int i) { + throw new UnsupportedOperationException(); + } + + @Override + public int indexOf(Object o) { + // TODO: make this function fast by using the underlying sorted set. This function should be constant. + ISeq s = seq(); + for(int i = 0; s != null; s = s.next(), i++) { + if(Util.equiv(s.first(), o)){ + return i; + } + } + return -1; + } + + @Override + public int lastIndexOf(Object o) { + // TODO: make this function fast by using the underlying sorted set. This function should be constant. + return reify().lastIndexOf(o); + } + + @Override + public ListIterator listIterator() { + return reify().listIterator(); + } + + @Override + public ListIterator listIterator(int index) { + return reify().listIterator(index); + } + + @Override + public List subList(int fromIndex, int toIndex) { + return reify().subList(fromIndex, toIndex); + } + + @Override + public boolean retainAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean removeAll(Collection collection) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean containsAll(Collection collection) { + for(Object o : collection) { + if(!contains(o)){ + return false; + } + } + return true; + } + + @Override + public Object[] toArray(Object[] objects) { + return RT.seqToPassedArray(seq(), objects); + } + + @Override + public Iterator iterator() { + return new SeqIterator(this); + } } diff --git a/test/book/test_PersistentSortedList.clj b/test/book/test_PersistentSortedList.clj index 08c9031..b6cbf55 100644 --- a/test/book/test_PersistentSortedList.clj +++ b/test/book/test_PersistentSortedList.clj @@ -1,10 +1,14 @@ (ns book.test-PersistentSortedList (:require [clojure.test :refer :all] - [book.match :refer [sorted-list sorted-list-by]])) + [book.util :refer [sorted-list sorted-list-by]])) (deftest test-match-buy-order-in-sell-book + (testing "constructing" + (is (empty? (map nil? (sorted-list))))) + ;; The following are tests that fails... + ;(is (empty? (vec (sorted-list))))) (testing "Test ordering." (is (= (sorted-list 1 2 3) (sorted-list 3 2 1))) (is (= (sorted-list 1 2 2 3) (sorted-list 3 2 1 2)))) @@ -16,7 +20,8 @@ (is (= (rest (sorted-list 1 2 3)) (sorted-list 2 3))) (is (= (rest (sorted-list 1 2 3 2)) (sorted-list 2 2 3))) (is (= (rest (sorted-list 1)) (list))) - (is (= (rest (sorted-list)) (list)))) + (is (empty? (rest (sorted-list)))) + (is (= (str (type (rest (sorted-list)))) "class book.PersistentSortedList"))) (testing "next" (is (= (next (sorted-list 1 2 3)) (sorted-list 2 3))) (is (= (next (sorted-list 1 2 3 2)) (sorted-list 2 2 3)))