/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /* $Rev$ $Date$ */ #ifndef tuscany_list_hpp #define tuscany_list_hpp /** * Simple list functions. */ #include #include "string.hpp" #include "fstream.hpp" #include "function.hpp" namespace tuscany { #ifdef WANT_MAINTAINER_COUNTERS /** * Debug utilities. Counters used to track instances of lists. */ long countLists = 0; long countILists = 0; long countCLists = 0; long countELists = 0; inline const bool resetListCounters() noexcept { countLists = countILists = countCLists = countELists = 0; return true; } inline const bool checkListCounters() noexcept { return countLists == 0; } inline const bool printListCounters() noexcept { cout << "countLists " << countLists << endl; cout << "countELists " << countELists << endl; cout << "countILists " << countILists << endl; cout << "countCLists " << countCLists << endl; return true; } #else #define resetListCounters() #define checkListCounters() true #define printListCounters() #endif #ifdef WANT_MAINTAINER_WATCH /** * Debug utilities. Macro used to write the contents of a list to * a string, easier to watch in a debugger than the list itself. */ #define debug_watchList() do { \ this->watch = watchList(*this); \ } while (0) #else #define debug_watchList(); #endif /** * A car/cdr lisp-like pair, base structure to construct lists. */ template class list { public: inline list() noexcept : car() { debug_inc(countLists); debug_inc(countELists); debug_watchList(); } inline list(const T& car, const lambda()>& cdr) noexcept : car(car), cdr(cdr) { debug_inc(countLists); debug_inc(countILists); debug_watchList(); } inline list(const list& p) noexcept : car(p.car), cdr(p.cdr) { debug_inc(countLists); debug_inc(countCLists); #ifdef WANT_MAINTAINER_WATCH watch = p.watch; #endif } list& operator=(const list& p) = delete; inline ~list() noexcept { debug_dec(countLists); } inline const bool operator==(const list& p) const noexcept { if(this == &p) return true; if(isNull(cdr)) return isNull(p.cdr); if(isNull(p.cdr)) return false; if(!(car == p.car)) return false; if(cdr == p.cdr) return true; return cdr() == p.cdr(); } inline const bool operator<(const list& p) const noexcept { if(this == &p) return false; if (isNull(cdr)) return !isNull(p.cdr); if (isNull(p.cdr)) return false; if (car < p.car) return true; if (car != p.car) return false; return cdr() < p.cdr(); } inline const bool operator>(const list& p) const noexcept { if(this == &p) return false; if (isNull(cdr)) return false; if (isNull(p.cdr)) return true; if (car > p.car) return true; if (car != p.car) return false; return cdr() > p.cdr(); } inline const bool operator!=(const list& p) const noexcept { return !this->operator==(p); } inline operator const list >() const noexcept { return (list >)T(*this); } private: #ifdef WANT_MAINTAINER_WATCH template friend const string watchList(const list& p) noexcept; string watch; #endif template friend const bool isNull(const list& p) noexcept; template friend const X car(const list& p) noexcept; template friend const list cdr(const list& p) noexcept; const T car; const lambda()> cdr; }; #ifdef WANT_MAINTAINER_WATCH /** * Debug utility used to write the contents of a list to a string, easier * to watch than the list itself in a debugger. */ template inline const string watchList(const list& p) noexcept { if(isNull(p)) return "()"; odebugstream os; os << "(" << car(p) << " ...)"; return str(os); } #endif /** * Returns true if the given list is nil. */ template inline const bool isNull(const list& p) noexcept { return isNull(p.cdr); } /** * Write a list to an output stream. */ template inline ostream& writeHelper(ostream& out, const list& l) noexcept { if (isNull(l)) return out; out << " " << car(l); return writeHelper(out, cdr(l)); } template inline ostream& operator<<(ostream& out, const list& l) noexcept { if(isNull(l)) return out << "()"; out << "(" << car(l); writeHelper(out, cdr(l)); return out << ")"; } /** * Construct a (lazy) list from a value and a lambda function that returns the cdr. */ template inline const list cons(const T& car, const lambda()>& cdr) noexcept { return list (car, cdr); } /** * Construct a list from a value and a cdr list. */ template inline const list cons(const T& car, const list& cdr) noexcept { return list (car, result(cdr)); } /** * Cons variations for use with the reduce and reduceRight functions. */ template inline const list lcons(const list& cdr, const T& car) noexcept { return cons(car, cdr); } template inline const list rcons(const T& car, const list& cdr) noexcept { return cons(car, cdr); } /** * Construct a list of one value. */ template inline const list mklist(const T& car) noexcept { return list (car, result(list ())); } /** * Construct a list of two values. */ template inline const list mklist(const T& a, const T& b) noexcept { return cons(a, mklist(b)); } /** * Construct a list of three values. */ template inline const list mklist(const T& a, const T& b, const T& c) noexcept { return cons(a, cons(b, mklist(c))); } /** * Construct a list of four values. */ template inline const list mklist(const T& a, const T& b, const T& c, const T& d) noexcept { return cons(a, cons(b, cons(c, mklist(d)))); } /** * Construct a list of five values. */ template inline const list mklist(const T& a, const T& b, const T& c, const T& d, const T& e) noexcept { return cons(a, cons(b, cons(c, cons(d, mklist(e))))); } /** * Construct a list of six values. */ template inline const list mklist(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f) noexcept { return cons(a, cons(b, cons(c, cons(d, cons(e, mklist(f)))))); } /** * Returns the car of a list. */ template inline const T car(const list& p) noexcept { // Abort if trying to access the car of a nil list assertOrFail(!isNull(p.cdr)); return p.car; } /** * Returns the cdr of a list. */ template inline const list cdr(const list& p) noexcept { return p.cdr(); } /** * Returns the car of the cdr (the 2nd element) of a list. */ template inline const T cadr(const list& p) noexcept { return car(cdr(p)); } /** * Returns the 3rd element of a list. */ template inline const T caddr(const list& p) noexcept { return car(cdr(cdr(p))); } /** * Returns the 4th element of a list. */ template inline const T cadddr(const list& p) noexcept { return car(cdr(cdr(cdr(p)))); } /** * Returns the 5th element of a list. */ template inline const T caddddr(const list& p) noexcept { return car(cdr(cdr(cdr(cdr(p))))); } /** * Returns the 6th element of a list. */ template inline const T cadddddr(const list& p) noexcept { return car(cdr(cdr(cdr(cdr(cdr(p)))))); } /** * Returns the 7th element of a list. */ template inline const T caddddddr(const list& p) noexcept { return car(cdr(cdr(cdr(cdr(cdr(cdr(p))))))); } /** * Returns the 8th element of a list. */ template inline const T cadddddddr(const list& p) noexcept { return car(cdr(cdr(cdr(cdr(cdr(cdr(cdr(p)))))))); } /** * Returns a list of elements from the 3rd to the end of a list. */ template inline const list cddr(const list& p) noexcept { return cdr(cdr(p)); } /** * Returns a list of elements from the 4th to the end of a list. */ template inline const list cdddr(const list& p) noexcept { return cdr(cdr(cdr(p))); } /** * Returns a list of elements from the 5th to the end of a list. */ template inline const list cddddr(const list& p) noexcept { return cdr(cdr(cdr(cdr(p)))); } /** * Returns a list of elements from the 6th to the end of a list. */ template inline const list cdddddr(const list& p) noexcept { return cdr(cdr(cdr(cdr(cdr(p))))); } /** * Returns a list of elements from the 7th to the end of a list. */ template inline const list cddddddr(const list& p) noexcept { return cdr(cdr(cdr(cdr(cdr(cdr(p)))))); } /** * Returns a list of elements from the 8th to the end of a list. */ template inline const list cdddddddr(const list& p) noexcept { return cdr(cdr(cdr(cdr(cdr(cdr(cdr(p))))))); } /** * Returns the length of a list. */ template inline const size_t length(const list& p) noexcept { const lambda&)> lengthRef = [&lengthRef](const size_t c, const list& p) -> const size_t { if(isNull(p)) return c; return lengthRef(c + 1, cdr(p)); }; return lengthRef(0, p); } /** * Appends a list and a lambda function returning a list. */ template inline const list append(const list&a, const lambda()>& fb) noexcept { if(isNull(a)) return fb(); return cons(car(a), [a, fb]() { return append(cdr(a), fb); }); } /** * Appends two lists. */ template inline const list append(const list&a, const list& b) noexcept { return append(a, result(b)); } /** * Append a value to a list. */ template inline const list operator+(const list& l, const T& v) noexcept { return append(l, mklist(v)); } template const list inline operator+(const list& l, const V& v) noexcept { return append(l, mklist(v)); } /** * Run a map lambda function on a list. */ template inline const list map(const lambda& f, const list& p) noexcept { if(isNull(p)) return list (); return cons(f(car(p)), map(f, cdr(p))); } /** * Run a reduce lambda function on a list. */ template inline const R reduce(const lambda& f, const R& initial, const list& p) noexcept { const lambda&p)> reduceAccumulate = [f, &reduceAccumulate](const R& acc, const list& p) -> R { if(isNull(p)) return acc; return reduceAccumulate(f(acc, car(p)), cdr(p)); }; return reduceAccumulate(initial, p); } template inline const R reduceRight(const lambda& f, const R& initial, const list& p) noexcept { const lambda&p, const R&)> reduceRightAccumulate = [f, &reduceRightAccumulate](const list& p, const R& acc) -> R { if(isNull(p)) return acc; return reduceRightAccumulate(cdr(p), f(car(p), acc)); }; return reduceRightAccumulate(p, initial); } /** * Run a filter lambda function on a list. */ template inline const list filter(const lambda& f, const list& p) noexcept { if(isNull(p)) return list (); if(f(car(p))) { const lambda(const lambda, const list)> ff(filter); return cons(car(p), curry(ff, f, cdr(p))); } return filter(f, cdr(p)); } /** * Returns a list pointing to a member of a list. */ template inline const list member(const T& t, const list& p) noexcept { if(isNull(p)) return list (); if(t == car(p)) return p; return member(t, cdr(p)); } /** * Reverse a list. */ template inline const list reverseIter(const list& acc, const list& p) noexcept { if(isNull(p)) return acc; return reverseIter(cons(car(p), acc), cdr(p)); } template inline const list reverse(const list& p) noexcept { return reverseIter(list (), p); } /** * Returns a sequence of values between the given bounds. */ template inline const list seq(const T& start, const T& end) noexcept { if(start == end) return mklist(start); if(start < end) return cons(start, [start, end] { return seq (start + 1, end); }); return cons(start, [start, end] { return seq (start - 1, end); }); } /** * Returns the i-th element of a list. */ template inline const T listRef(const list& l, const size_t i) noexcept { if(i == 0) return car(l); return listRef(cdr(l), i - 1); } /** * Returns a new list consisting of the first k elements of a list. */ template inline const list listHead(const list& l, const size_t k) noexcept { if(k == 0) return list(); if(isNull(l)) return l; return cons(car(l), listHead(cdr(l), k - 1)); } /** * Returns the tail of a list, ommiting the first k elements. */ template inline const list listTail(const list& l, const size_t k) noexcept { if(k == 0) return l; if(isNull(l)) return l; return listTail(cdr(l), k - 1); } /** * Substitute elements in a list. */ template inline const list subst(const T& o, const T& n, const list& p) noexcept { if(isNull(p)) return p; if(o == car(p)) return cons(n, subst(o, n, cdr(p))); return cons(car(p), subst(o, n, cdr(p))); } /** * Returns the first pair matching a key from a list of key value pairs. */ template inline const list assoc(const T& k, const list >& p) noexcept { if(isNull(p)) return list(); if(k == car(car(p))) return car(p); return assoc(k, cdr(p)); } /** * Returns the first pair matching a key from a list of key value pairs. * Requires T to support isList and cast to list. */ template inline const list assoc(const T& k, const list& p) noexcept { if(isNull(p)) return list(); const T c = car(p); if(isList(c) && k == car(c)) return c; return assoc(k, cdr(p)); } /** * Returns a list of lists containing elements from two input lists. */ template inline const list > zip(const list& a, const list& b) noexcept { if (isNull(a) || isNull(b)) return list >(); return cons >(mklist(car(a), car(b)), zip(cdr(a), cdr(b))); } /** * Converts a list of key value pairs to a list containing the list of keys and the list of values. */ template inline const list unzipKeys(const list >& l) noexcept { if (isNull(l)) return list(); return cons(car(car(l)), unzipKeys(cdr(l))); } template inline const list unzipValues(const list >& l) noexcept { if (isNull(l)) return list(); return cons(cadr(car(l)), unzipValues(cdr(l))); } template inline const list > unzip(const list >& l) noexcept { return mklist >(unzipKeys(l), unzipValues(l)); } /** * Delete assocs matching a key from a list of assocs. */ template inline const list > delAssoc(const T& k, const list >& p) noexcept { if(isNull(p)) return p; if(k == car(car(p))) return delAssoc(k, cdr(p)); return cons >(car(p), delAssoc(k, cdr(p))); } /** * Delete assocs matching a key from a list of assocs. * Requires T to support isList, isAssoc, and cast to list. */ template inline const list delAssoc(const T& k, const list& p) noexcept { if(isNull(p)) return p; const T c = car(p); if(isList(c) && k == car(c)) return delAssoc(k, cdr(p)); return cons(c, delAssoc(k, cdr(p))); } /** * Substitute assocs with matching keys in a list of assocs. */ template inline const list > substAssoc(const T& k, const list& n, const list >& p, const bool add = false) noexcept { if(isNull(p)) return add? mklist >(n) : p; if(k == car(car(p))) return cons >(n, substAssoc(k, n, cdr(p), false)); return cons >(car(p), substAssoc(k, n, cdr(p), add)); } /** * Substitute assocs with matching keys in a list of assocs. * Requires T to support isList, isAssoc, and cast to list. */ template inline const list substAssoc(const T& k, const list& n, const list& p, const bool add = false) noexcept { if(isNull(p)) return add? mklist(n) : p; const T c = car(p); if(isList(c) && k == car(c)) return cons(n, substAssoc(k, n, cdr(p), false)); return cons(c, substAssoc(k, n, cdr(p), add)); } } #endif /* tuscany_list_hpp */