├── .gitignore ├── CMakeLists.txt ├── README.md ├── conf.hh ├── exceptions.hh ├── hashmap.cc ├── hashmap.hh ├── list.cc ├── list.hh ├── main.cc ├── object.cc ├── object.hh ├── persistent_arraymap.cc ├── persistent_arraymap.hh ├── seq.cc ├── seq.hh ├── vector.cc └── vector.hh /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | *.kdev4 3 | *kate-swp 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | PROJECT (xt) 2 | 3 | find_package(Boost REQUIRED COMPONENTS regex) 4 | 5 | CMAKE_MINIMUM_REQUIRED(VERSION 2.8) # fucking piece of shit of a build system shut the fuck up 6 | 7 | if (UNIX) 8 | add_definitions(-Wall -g -DUNIX -lc_g) 9 | else (UNIX) 10 | add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_SCL_SECURE_NO_WARNINGS) 11 | endif (UNIX) 12 | 13 | set (SOURCES object seq vector list persistent_arraymap main) 14 | 15 | set_source_files_properties(${SOURCES} PROPERTIES COMPILE_FLAGS "-std=c++0x") 16 | 17 | add_executable(xtc ${SOURCES}) 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C++ implementations of Clojure's [persistent data structures](http://clojure.org/data_structures). 2 | 3 | Like their Clojure counterparts, these structures are dynamic. They are accessed via smart pointers and all memory is managed. 4 | 5 | Based on the Clojure [implementation](http://github.com/clojure/clojure). 6 | 7 | Statically typed versions with better runtime guarantees are planned, depending on how this pans out. 8 | 9 | The implementations aren't yet complete. 10 | 11 | # Usage 12 | 13 | ## Vector 14 | 15 | `v = xt::vector::vec({1, 2, 3}) => [1, 2, 3]` 16 | 17 | `v2 = xt::vector::conj(v, 4) => [1, 2, 3, 4]` 18 | 19 | `v3 = xt::vector::assocN(v, 1, 5) => [1, 5, 3]` 20 | 21 | `xt::vector::nth(v, 1) => 2` 22 | 23 | `xt::vector::vec({v, v2, v3}) => [[1, 2, 3], [1, 2, 3, 4], [1, 5, 3]]` 24 | 25 | `for (int i = 0; i < xt::vector::len(v); ++i) xt::vector::nth(i);` 26 | -------------------------------------------------------------------------------- /conf.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_CONF_H_ 2 | #define _XT_CONF_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef char byte; 11 | typedef unsigned char ubyte; 12 | typedef unsigned char xt_byte; 13 | 14 | enum class Type : unsigned char { 15 | Nil, 16 | Boolean, 17 | Number, 18 | Pointer, 19 | Char, 20 | Other 21 | }; 22 | 23 | struct TypeInfo { 24 | std::string name; 25 | }; 26 | 27 | template 28 | int index_of(const std::vector& v, const T& val) { 29 | int idx = 0; 30 | for (typename std::vector::const_iterator it = v.cbegin(); it != v.cend(); ++it) { 31 | if (*it == val) return idx; 32 | idx++; 33 | } 34 | return -1; 35 | } 36 | 37 | template 38 | bool has_key(const std::unordered_map m, const K& k) { 39 | for (auto it = m.begin(); it != m.end(); ++it) { 40 | if (k == it->first) return true; 41 | } 42 | return false; 43 | } 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /exceptions.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_EXCEPTIONS_HH_ 2 | #define _XT_EXCEPTIONS_HH_ 3 | 4 | #include 5 | #include 6 | 7 | namespace xt { 8 | 9 | class RuntimeException: public std::exception { 10 | std::string data; 11 | public: 12 | RuntimeException(const std::string& error) : data(error) {}; 13 | virtual ~RuntimeException() throw() {}; 14 | 15 | inline virtual const char* what() const throw() {return data.c_str();}; 16 | }; 17 | 18 | } 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /hashmap.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "hashmap.hh" 3 | -------------------------------------------------------------------------------- /hashmap.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_HASHMAP_HH_ 2 | #define _XT_HASHMAP_HH_ 3 | 4 | #include 5 | #include "object.hh" 6 | 7 | namespace xt { 8 | 9 | class _INode; 10 | typedef std::shared_ptr<_INode> INode; 11 | class _INode : public std::enable_shared_from_this { 12 | INode assoc(int shift, int hash, Object key, Object val, Object leaf) = 0; 13 | }; 14 | 15 | struct _HashMap { 16 | const int count; 17 | const bool hasNil; 18 | const Object nilValue; 19 | }; 20 | 21 | typedef std::shared_ptr<_HashMap> HashMap; 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /list.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "list.hh" 3 | 4 | namespace xt { 5 | TypeInfo _List::type_info { "List" }; 6 | namespace list { 7 | 8 | static List EMPTY = List(new _List {Object(), List(), 0}); 9 | 10 | List cons(Object o) { 11 | return cons(EMPTY, o); 12 | } 13 | 14 | List cons(List list, Object o) { 15 | return List(new _List {o, list, list->count+1}); 16 | } 17 | 18 | List empty() { 19 | return EMPTY; 20 | } 21 | 22 | } 23 | 24 | Object LSeq::first() const { return l->first; } 25 | Seq LSeq::next() const { if (l->rest) return Seq(new LSeq(l->rest)); return Seq(); } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /list.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_LIST_H_ 2 | #define _XT_LIST_H_ 3 | 4 | #include "object.hh" 5 | #include "exceptions.hh" 6 | #include "seq.hh" 7 | 8 | 9 | namespace xt { 10 | struct _List; 11 | struct _List { 12 | _List(Object first, std::shared_ptr<_List> rest, int count) : first(first), count(count), rest(rest) { } 13 | const Object first; 14 | const int count; 15 | const std::shared_ptr<_List> rest; 16 | static TypeInfo type_info; 17 | }; 18 | typedef std::shared_ptr<_List> List; 19 | 20 | class LSeq : public ISeq { 21 | public: 22 | const List l; 23 | LSeq(const List l): l(l) {} 24 | virtual Object first() const; 25 | virtual Seq next() const; 26 | }; 27 | 28 | namespace list { 29 | 30 | List cons(Object o); 31 | List cons(List list, Object o); 32 | inline bool is_list(Object o) { return o.typeinfo == &_List::type_info; } 33 | inline Seq to_seq(List l) { return Seq(new LSeq(l)); } 34 | inline List to_list(Object o) { if (!is_list(o)) throw RuntimeException("Not a List"); return std::static_pointer_cast<_List>(o.ptr); } 35 | List empty(); 36 | 37 | } 38 | } 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /main.cc: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char* argv[]) { 3 | return 0; 4 | } 5 | -------------------------------------------------------------------------------- /object.cc: -------------------------------------------------------------------------------- 1 | #include "object.hh" 2 | 3 | namespace xt { 4 | 5 | // // static TypeInfo number_type = TypeInfo { "Number" }; 6 | // TypeInfo bool_type; 7 | // TypeInfo char_type; 8 | // TypeInfo nil_type; 9 | 10 | ObjectArray new_object_array(unsigned int size) { 11 | auto o = ObjectArray(new std::vector); 12 | if (size != 0) o->reserve(size); 13 | return o; 14 | } 15 | 16 | Object::Object(const Object& o) { 17 | type = o.type; 18 | if (type == Type::Boolean) b = o.b; 19 | if (type == Type::Number) number = o.number; 20 | if (type == Type::Char) ch = o.ch; 21 | if (type == Type::Pointer) new (&ptr) std::shared_ptr(o.ptr); 22 | typeinfo = o.typeinfo; 23 | } 24 | 25 | Object& Object::operator=(const Object& o) { 26 | type = o.type; 27 | if (type == Type::Boolean) b = o.b; 28 | if (type == Type::Number) number = o.number; 29 | if (type == Type::Char) ch = o.ch; 30 | if (type == Type::Pointer) new (&ptr) std::shared_ptr(o.ptr); 31 | typeinfo = o.typeinfo; 32 | return *this; 33 | } 34 | 35 | Object::operator bool() const { 36 | if (type == Type::Nil) return false; 37 | if (type == Type::Boolean) return b; 38 | if (type == Type::Number) return true; 39 | if (type == Type::Char) return true; 40 | if (type == Type::Pointer) return !!ptr; 41 | return false; 42 | } 43 | 44 | 45 | } 46 | -------------------------------------------------------------------------------- /object.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_OBJECT_HH_ 2 | #define _XT_OBJECT_HH_ 3 | 4 | #include "conf.hh" 5 | 6 | #include 7 | #include 8 | 9 | namespace xt { 10 | 11 | static TypeInfo bool_type { "Boolean" }; 12 | static TypeInfo char_type { "Char" }; 13 | static TypeInfo number_type { "Number"}; 14 | static TypeInfo nil_type { "Nil" }; 15 | 16 | struct Object { 17 | Object() : type(Type::Nil), typeinfo(&nil_type) {} 18 | Object(const Object& o); 19 | explicit Object(bool b) : type(Type::Boolean), typeinfo(&bool_type), b(b) {} 20 | explicit Object(int n) : type(Type::Number), typeinfo(&number_type), number(n) {} 21 | explicit Object(double n) : type(Type::Number), typeinfo(&number_type), number(n) {} 22 | explicit Object(char ch) : type(Type::Char), typeinfo(&char_type), ch(ch) {} 23 | Object(void* t, TypeInfo* ti) : type(Type::Pointer), typeinfo(ti), raw(t) {} 24 | template 25 | Object(std::shared_ptr t, TypeInfo* ti) : type(Type::Pointer), typeinfo(ti), ptr(t) {} 26 | template 27 | Object(std::shared_ptr t) : type(Type::Pointer), typeinfo(&T::type_info), ptr(t) {} 28 | Object& operator=(const Object& o); 29 | 30 | bool operator==(const Object& o2) const { return type == o2.type && typeinfo == o2.typeinfo && number == o2.number; } 31 | 32 | ~Object() {} 33 | operator bool() const; 34 | Type type; 35 | TypeInfo* typeinfo; 36 | union { 37 | double number; 38 | bool b; 39 | char ch; 40 | void* raw; 41 | std::shared_ptr ptr; 42 | }; 43 | }; 44 | 45 | typedef std::vector _ObjectArray; 46 | typedef std::shared_ptr<_ObjectArray> ObjectArray; 47 | 48 | ObjectArray new_object_array(unsigned int size = 0); 49 | 50 | } 51 | 52 | namespace std { 53 | template<> 54 | struct hash { 55 | std::size_t operator()(xt::Object const &key) { 56 | return hash()(key.ptr.get()); 57 | } 58 | }; 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /persistent_arraymap.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "persistent_arraymap.hh" 3 | 4 | #include 5 | 6 | 7 | namespace xt { 8 | namespace map { 9 | 10 | // static ArrayMap* empty_arraymap = nullptr; 11 | // 12 | // ArrayMap* new_arraymap(XT_State* xt, Array* array) { 13 | // // ArrayMap* map = (ArrayMap*)xt_gc_alloc(xt, sizeof(arraymap), Type::Map); 14 | // auto map = xt::gc::alloc(xt, Type::Map); 15 | // map->array = array; 16 | // xt::gc::link(xt, obj2gco(map)); 17 | // return map; 18 | // } 19 | // 20 | // ArrayMap* empty(XT_State* xt) { 21 | // if (!empty_arraymap) empty_arraymap = new_arraymap(xt, array_new(xt, 32)); 22 | // return empty_arraymap; 23 | // } 24 | // 25 | // int indexOf(ArrayMap* map, xt_value* key) { 26 | // int i; 27 | // for (i = 0; i < map->array->count; i+=2) { 28 | // if (xt_equiv(key, array_get(map->array, i))) return i; 29 | // } 30 | // return -1; 31 | // } 32 | // 33 | // xt_value* getik(ArrayMap* map, int idx) { 34 | // return array_get(map->array, idx*2); 35 | // } 36 | // 37 | // xt_value* getiv(ArrayMap* map, int idx) { 38 | // return array_get(map->array, (idx*2)+1); 39 | // } 40 | // 41 | // ArrayMap* assoc(XT_State* xt, ArrayMap* map, xt_value* key, xt_value* val) { 42 | // int i = indexOf(map, key); 43 | // Array* newarray; 44 | // if (i >= 0) { 45 | // if (xt_equiv(array_get(map->array, i+1), val)) return map; 46 | // newarray = array_copy(xt, map->array); 47 | // array_append(newarray, key); 48 | // array_append(newarray, val); 49 | // } else { 50 | // newarray = array_copy(xt, map->array); 51 | // array_append(newarray, key); 52 | // array_append(newarray, val); 53 | // } 54 | // return new_arraymap(xt, newarray); 55 | // } 56 | // 57 | // int len(ArrayMap* map) { 58 | // return map->array->count/2; 59 | // } 60 | // 61 | // xt_value* get(ArrayMap* map, xt_value* key) { 62 | // int i = indexOf(map, key); 63 | // if (i >= 0) return array_get(map->array, i+1); 64 | // return nil_value(); 65 | // } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /persistent_arraymap.hh: -------------------------------------------------------------------------------- 1 | #ifndef _PERSISTENT_ARRAYMAP_H_ 2 | #define _PERSISTENT_ARRAYMAP_H_ 3 | 4 | #include "conf.hh" 5 | #include "object.hh" 6 | #include 7 | 8 | struct xt_value; 9 | struct XT_State; 10 | namespace xt { 11 | 12 | // struct ArrayMap : Object { 13 | // std::vector array; 14 | // }; 15 | // typedef std::shared_ptr ArrayMapHandle; 16 | // namespace map { 17 | // 18 | // ArrayMapHandle empty(); 19 | // ArrayMapHandle assoc(ArrayMapHandle map, ObjectHandle key, ObjectHandle value); 20 | // ObjectHandle get(const ArrayMapHandle& map, ObjectHandle key); 21 | // ObjectHandle getik(const ArrayMapHandle& map, int idx); 22 | // ObjectHandle getiv(const ArrayMapHandle& map, int idx); 23 | // int len(const ArrayMapHandle& map); 24 | 25 | // } 26 | } 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /seq.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "seq.hh" 3 | 4 | namespace xt { 5 | namespace seq { 6 | 7 | bool contains(Seq s, Object o) { 8 | while (s) { 9 | if (s->first() == o) return true; 10 | s = s->next(); 11 | } 12 | return false; 13 | } 14 | 15 | int index_of(Seq s, Object o) { 16 | int idx = 0; 17 | while (s) { 18 | if (s->first() == o) return idx; 19 | idx++; 20 | s = s->next(); 21 | } 22 | return -1; 23 | } 24 | 25 | } 26 | } -------------------------------------------------------------------------------- /seq.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_SEQ_HH_ 2 | #define _XT_SEQ_HH_ 3 | 4 | #include "object.hh" 5 | 6 | namespace xt { 7 | 8 | class ISeq; 9 | typedef std::shared_ptr Seq; 10 | class ISeq { 11 | public: 12 | virtual Object first() const = 0; 13 | virtual Seq next() const = 0; 14 | }; 15 | 16 | namespace seq { 17 | 18 | bool contains(Seq s, Object o); 19 | int index_of(Seq s, Object o); 20 | 21 | } 22 | 23 | } 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /vector.cc: -------------------------------------------------------------------------------- 1 | 2 | #include "vector.hh" 3 | #include "exceptions.hh" 4 | 5 | namespace xt { 6 | TypeInfo _Vector::type_info { "Vector" }; 7 | TypeInfo _Node::type_info { "VectorNode" }; 8 | namespace vector { 9 | 10 | static Node EMPTY_NODE; 11 | static Vector EMPTY; 12 | 13 | Vector vec(List list) { 14 | if (list->count == 0) return empty(); 15 | Vector ret = vector::conj(list->first); 16 | List n = list->rest; 17 | while (n && n->count) { 18 | ret = conj(ret, n->first); 19 | n = n->rest; 20 | } 21 | return ret; 22 | 23 | } 24 | 25 | unsigned int tailoff(Vector v) { 26 | if (v->cnt < 32) return 0; 27 | return ((v->cnt-1) >> 5) << 5; 28 | } 29 | 30 | Node empty_node() { 31 | if (!EMPTY_NODE) { 32 | EMPTY_NODE = Node(new _Node {new_object_array(32)}); 33 | } 34 | return EMPTY_NODE; 35 | } 36 | 37 | Vector empty() { 38 | if (!EMPTY) { 39 | EMPTY = Vector(new _Vector {0, 5, empty_node(), new_object_array()}); 40 | } 41 | return EMPTY; 42 | } 43 | 44 | ObjectArray arrayFor(Vector v, unsigned int i) { 45 | if (i < v->cnt) { 46 | if (i >= tailoff(v)) return v->tail; 47 | Node node = v->root; 48 | for (int level = v->shift; level > 0; level -= 5) 49 | node = to_node((*node->array)[(i >> level) & 0x01f]); 50 | return node->array; 51 | } 52 | throw RuntimeException("Index out of bounds"); 53 | } 54 | 55 | Object nth(Vector v, unsigned int i) { 56 | return (*arrayFor(v, i))[i & 0x01f]; 57 | } 58 | 59 | Object nth(Vector v, unsigned int i, Object notFound) { 60 | if (i < v->cnt) return nth(v, i); 61 | return notFound; 62 | } 63 | 64 | Node doAssoc(unsigned int level, Node node, unsigned int i, Object val) { 65 | Node ret = Node(new _Node {new_object_array(32)}); 66 | std::copy(node->array->begin(), node->array->end(), ret->array->begin()); 67 | if (level == 0) 68 | (*ret->array)[i & 0x01f] = val; 69 | else { 70 | unsigned int subidx = (i >> level) & 0x01f; 71 | (*ret->array)[subidx] = doAssoc(level - 5, to_node((*node->array)[subidx]), i, val); 72 | } 73 | return ret; 74 | } 75 | 76 | Object assocN(Vector v, unsigned int i, Object val) { 77 | if (i < v->cnt) { 78 | if (i >= tailoff(v)) { 79 | ObjectArray newTail = new_object_array(v->tail->size()); 80 | *newTail = *v->tail; 81 | (*newTail)[i & 0x01f] = val; 82 | return Vector(new _Vector {v->cnt, v->shift, v->root, newTail}); 83 | } 84 | return Vector(new _Vector {v->cnt, v->shift, doAssoc(v->shift, v->root, i, val), v->tail}); 85 | } 86 | if (i == v->cnt) return conj(v, val); 87 | throw RuntimeException("Index out of bounds"); 88 | } 89 | 90 | Node newPath(unsigned int level, Node node) { 91 | if (level == 0) return node; 92 | Node ret = Node(new _Node); 93 | (*ret->array)[0] = newPath(level - 5, node); 94 | return ret; 95 | } 96 | 97 | Node pushTail(Vector v, unsigned int level, Node parent, Node tailnode) { 98 | unsigned int subidx = ((v->cnt -1) >> level) & 0x01f; 99 | Node ret = Node(new _Node); 100 | std::copy(parent->array->begin(), parent->array->end(), ret->array->begin()); 101 | Node nodeToInsert; 102 | if (level == 5) 103 | nodeToInsert = tailnode; 104 | else { 105 | Node child = to_node((*parent->array)[subidx]); 106 | nodeToInsert = (child != nullptr) ? pushTail(v, level - 5, child, tailnode) : newPath(level - 5, tailnode); 107 | } 108 | (*ret->array)[subidx] = nodeToInsert; 109 | return ret; 110 | } 111 | 112 | Vector conj(Object val) { 113 | return conj(empty(), val); 114 | } 115 | 116 | Vector conj(Vector v, Object val) { 117 | if (v->cnt - tailoff(v) < 32) { 118 | ObjectArray newTail = new_object_array(v->tail->size()+1); 119 | *newTail = *v->tail; 120 | newTail->push_back(val); 121 | return Vector(new _Vector {v->cnt + 1, v->shift, v->root, newTail}); 122 | } 123 | Node newroot; 124 | Node tailnode = Node(new _Node { v->tail }); 125 | unsigned int newshift = v->shift; 126 | if ((v->cnt >> 5) > (1 << v->shift)) { 127 | newroot = Node(new _Node); 128 | (*newroot->array)[0] = v->root; 129 | (*newroot->array)[1] = newPath(v->shift, tailnode); 130 | newshift += 5; 131 | } 132 | else newroot = pushTail(v, v->shift, v->root, tailnode); 133 | return Vector(new _Vector {v->cnt+1, newshift, newroot, ObjectArray(new _ObjectArray{val})}); 134 | } 135 | 136 | } 137 | 138 | Object VSeq::first() const { return vector::nth(v, index); } 139 | Seq VSeq::next() const { if (index+1 < v->cnt) return Seq(new VSeq(v, index+1)); return Seq(); } 140 | 141 | } 142 | -------------------------------------------------------------------------------- /vector.hh: -------------------------------------------------------------------------------- 1 | #ifndef _XT_VECTOR_HH_ 2 | #define _XT_VECTOR_HH_ 3 | 4 | #include "conf.hh" 5 | #include "object.hh" 6 | #include "list.hh" 7 | #include "seq.hh" 8 | 9 | #include 10 | #include 11 | 12 | namespace xt { 13 | 14 | struct _Node { 15 | _Node() { array = new_object_array(32); } 16 | _Node(ObjectArray array) : array(array) {} 17 | ObjectArray array; 18 | static TypeInfo type_info; 19 | }; 20 | 21 | typedef std::shared_ptr<_Node> Node; 22 | 23 | inline Node to_node(Object o) { return std::static_pointer_cast<_Node>(o.ptr); } 24 | 25 | struct _Vector { 26 | _Vector(unsigned int cnt, unsigned int shift, Node root, ObjectArray tail) : cnt(cnt), shift(shift), root(root), tail(tail) {} 27 | const unsigned int cnt; 28 | const unsigned int shift; 29 | const Node root; 30 | const ObjectArray tail; 31 | static TypeInfo type_info; 32 | }; 33 | 34 | typedef std::shared_ptr<_Vector> Vector; 35 | 36 | class VSeq : public ISeq { 37 | public: 38 | const Vector v; 39 | const unsigned int index; 40 | VSeq(Vector v) : v(v), index(0) {} 41 | VSeq(Vector v, unsigned int index) : v(v), index(index) {} 42 | virtual Object first() const; 43 | virtual Seq next() const; 44 | }; 45 | 46 | namespace vector { 47 | 48 | ///returns the empty vector [] 49 | Vector empty(); 50 | 51 | ///retruns new vector with val appended 52 | Vector conj(Vector v, Object val); 53 | 54 | ///returns new vector containing val (appends to empty vector) 55 | Vector conj(Object val); 56 | 57 | ///returns new vector containing values in list 58 | template 59 | Vector vec(std::initializer_list list) { 60 | auto v = empty(); 61 | for (auto i: list) v = conj(v, Object(i)); 62 | return v; 63 | } 64 | 65 | ///returns vector from list 66 | Vector vec(List list); 67 | 68 | inline bool is_vector(Object o) { return o.typeinfo == &_Vector::type_info; } 69 | inline Vector to_vec(Object o) { if (!is_vector(o)) throw RuntimeException("Not a Vector"); return std::static_pointer_cast<_Vector>(o.ptr); } 70 | inline Seq to_seq(Vector v) { return Seq(new VSeq(v)); } 71 | 72 | ///gets the length of a vector 73 | inline int len(Vector v) { return v->cnt; } 74 | 75 | ///returns the nth element of a vector 76 | Object nth(Vector v, unsigned int i); 77 | 78 | ///returns the nth element of a vector, or notFound if index is out of bounds 79 | Object nth(Vector v, unsigned int i, Object notFound); 80 | 81 | ///returns a new vector with v[i] == val 82 | Object assocN(Vector v, unsigned int i, Object val); 83 | 84 | } 85 | } 86 | 87 | #endif 88 | --------------------------------------------------------------------------------