187 lines
6.4 KiB
C++
187 lines
6.4 KiB
C++
/*
|
|
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura
|
|
*/
|
|
#include <vector>
|
|
#include "library/parray.h"
|
|
#include "library/vm/vm.h"
|
|
#include "library/vm/vm_nat.h"
|
|
|
|
namespace lean {
|
|
struct vm_array : public vm_external {
|
|
parray<vm_obj> m_array;
|
|
vm_array(parray<vm_obj> const & a):m_array(a) {}
|
|
virtual ~vm_array() {}
|
|
virtual void dealloc() override { this->~vm_array(); get_vm_allocator().deallocate(sizeof(vm_array), this); }
|
|
virtual vm_external * ts_clone(vm_clone_fn const &) override;
|
|
virtual vm_external * clone(vm_clone_fn const &) override { lean_unreachable(); }
|
|
};
|
|
|
|
/* Auxiliary object used by vm_array::ts_clone.
|
|
This is the "thread safe" version used when creating a ts_vm_obj that contains
|
|
a nested vm_array. */
|
|
struct vm_array_ts_copy : public vm_external {
|
|
std::vector<vm_obj> m_entries;
|
|
virtual ~vm_array_ts_copy() {
|
|
/* The object ts_vm_obj manages the life cycle of all vm_obj's.
|
|
We should prevent this destructor from invoking the destructor of
|
|
vm_obj's nested in m_entries. */
|
|
for (auto & p : m_entries) {
|
|
p.steal_ptr();
|
|
}
|
|
}
|
|
virtual void dealloc() override { lean_unreachable(); }
|
|
virtual vm_external * ts_clone(vm_clone_fn const &) override { lean_unreachable(); }
|
|
virtual vm_external * clone(vm_clone_fn const &) override;
|
|
};
|
|
|
|
vm_external * vm_array::ts_clone(vm_clone_fn const & fn) {
|
|
vm_array_ts_copy * r = new vm_array_ts_copy();
|
|
size_t sz = m_array.size();
|
|
for (size_t i = 0; i < sz; i++) {
|
|
r->m_entries.emplace_back(fn(m_array[i]));
|
|
}
|
|
return r;
|
|
}
|
|
|
|
vm_external * vm_array_ts_copy::clone(vm_clone_fn const & fn) {
|
|
parray<vm_obj> array;
|
|
for (vm_obj const & p : m_entries) {
|
|
array.push_back(fn(p));
|
|
}
|
|
return new (get_vm_allocator().allocate(sizeof(vm_array))) vm_array(array);
|
|
}
|
|
|
|
parray<vm_obj> const & to_array(vm_obj const & o) {
|
|
lean_vm_check(dynamic_cast<vm_array*>(to_external(o)));
|
|
return static_cast<vm_array*>(to_external(o))->m_array;
|
|
}
|
|
|
|
vm_obj to_obj(parray<vm_obj> const & a) {
|
|
return mk_vm_external(new (get_vm_allocator().allocate(sizeof(vm_array))) vm_array(a));
|
|
}
|
|
|
|
vm_obj array_read(vm_obj const &, vm_obj const &, vm_obj const & a, vm_obj const & i) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned idx = force_to_unsigned(i);
|
|
lean_vm_check(idx < to_array(a).size());
|
|
parray<vm_obj> const & _a = to_array(a);
|
|
return _a[idx];
|
|
}
|
|
|
|
vm_obj array_write(vm_obj const &, vm_obj const &, vm_obj const & a, vm_obj const & i, vm_obj const & v) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned idx = force_to_unsigned(i);
|
|
parray<vm_obj> const & p = to_array(a);
|
|
lean_vm_check(idx < p.size());
|
|
if (a.raw()->get_rc() == 1) {
|
|
const_cast<parray<vm_obj> &>(p).set(idx, v);
|
|
return a;
|
|
} else {
|
|
parray<vm_obj> new_a = p;
|
|
new_a.set(idx, v);
|
|
return to_obj(new_a);
|
|
}
|
|
}
|
|
|
|
vm_obj array_push_back(vm_obj const &, vm_obj const &, vm_obj const & a, vm_obj const & v) {
|
|
parray<vm_obj> const & p = to_array(a);
|
|
if (a.raw()->get_rc() == 1) {
|
|
const_cast<parray<vm_obj> &>(p).push_back(v);
|
|
return a;
|
|
} else {
|
|
parray<vm_obj> new_a = p;
|
|
new_a.push_back(v);
|
|
return to_obj(new_a);
|
|
}
|
|
}
|
|
|
|
vm_obj array_pop_back(vm_obj const &, vm_obj const &, vm_obj const & a) {
|
|
parray<vm_obj> const & p = to_array(a);
|
|
if (a.raw()->get_rc() == 1) {
|
|
const_cast<parray<vm_obj> &>(p).pop_back();
|
|
return a;
|
|
} else {
|
|
parray<vm_obj> new_a = p;
|
|
new_a.pop_back();
|
|
return to_obj(new_a);
|
|
}
|
|
}
|
|
|
|
vm_obj mk_array(vm_obj const &, vm_obj const & n, vm_obj const & v) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned _n = force_to_unsigned(n);
|
|
parray<vm_obj> a(_n, v);
|
|
return to_obj(a);
|
|
}
|
|
|
|
vm_obj array_mk(vm_obj const &, vm_obj const & n, vm_obj const & fn) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned _n = force_to_unsigned(n);
|
|
parray<vm_obj> a;
|
|
for (unsigned i = 0; i < _n; ++i) {
|
|
a.push_back(invoke(fn, mk_vm_nat(i)));
|
|
}
|
|
return to_obj(a);
|
|
}
|
|
|
|
vm_obj array_foreach(vm_obj const &, vm_obj const & n, vm_obj const & a, vm_obj const & fn) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned _n = force_to_unsigned(n);
|
|
parray<vm_obj> const & p = to_array(a);
|
|
if (a.raw()->get_rc() == 1) {
|
|
parray<vm_obj> & _p = const_cast<parray<vm_obj> &>(p);
|
|
for (unsigned i = 0; i < _n; i++)
|
|
_p.set(i, invoke(fn, mk_vm_nat(i), _p[i]));
|
|
return a;
|
|
} else {
|
|
parray<vm_obj> new_a;
|
|
for (unsigned i = 0; i < _n; i++) {
|
|
new_a.push_back(invoke(fn, mk_vm_nat(i), p[i]));
|
|
}
|
|
return to_obj(new_a);
|
|
}
|
|
}
|
|
|
|
vm_obj array_iterate(vm_obj const &, vm_obj const &, vm_obj const & n,
|
|
vm_obj const & a, vm_obj const & b, vm_obj const & fn) {
|
|
/* TODO(Leo): handle case where n is too big */
|
|
unsigned _n = force_to_unsigned(n);
|
|
parray<vm_obj> const & p = to_array(a);
|
|
vm_obj r = b;
|
|
for (unsigned i = 0; i < _n; i++)
|
|
r = invoke(fn, mk_vm_nat(i), p[i], r);
|
|
return r;
|
|
}
|
|
|
|
static unsigned g_array_read_idx = -1;
|
|
|
|
unsigned array_cases_on(vm_obj const & o, buffer<vm_obj> & data) {
|
|
vm_obj d[3] = {o, mk_vm_unit(), mk_vm_unit()};
|
|
vm_obj fn = mk_vm_closure(g_array_read_idx, 3, d);
|
|
data.push_back(fn);
|
|
return 0;
|
|
}
|
|
|
|
void initialize_vm_array() {
|
|
DECLARE_VM_BUILTIN(name({"array", "mk"}), array_mk);
|
|
DECLARE_VM_BUILTIN(name({"mk_array"}), mk_array);
|
|
DECLARE_VM_BUILTIN(name({"array", "data"}), array_read);
|
|
DECLARE_VM_BUILTIN(name({"array", "read"}), array_read);
|
|
DECLARE_VM_BUILTIN(name({"array", "write"}), array_write);
|
|
DECLARE_VM_BUILTIN(name({"array", "push_back"}), array_push_back);
|
|
DECLARE_VM_BUILTIN(name({"array", "pop_back"}), array_pop_back);
|
|
DECLARE_VM_BUILTIN(name({"array", "foreach"}), array_foreach);
|
|
DECLARE_VM_BUILTIN(name({"array", "iterate"}), array_iterate);
|
|
DECLARE_VM_CASES_BUILTIN(name({"array", "cases_on"}), array_cases_on);
|
|
}
|
|
|
|
void finalize_vm_array() {
|
|
}
|
|
|
|
void initialize_vm_array_builtin_idxs() {
|
|
g_array_read_idx = *get_vm_builtin_idx(name({"array", "read"}));
|
|
}
|
|
}
|