From da5046100b4b01a0c4504b284370c562b7751de5 Mon Sep 17 00:00:00 2001 From: Matthew Constable Date: Sun, 3 Feb 2019 17:25:24 +0000 Subject: [PATCH] Able to create set from iterable. --- vm/src/frame.rs | 4 +-- vm/src/obj/objset.rs | 70 ++++++++++++++++++++------------------------ vm/src/pyobject.rs | 2 ++ 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/vm/src/frame.rs b/vm/src/frame.rs index 9a50f8875..eed72c796 100644 --- a/vm/src/frame.rs +++ b/vm/src/frame.rs @@ -230,10 +230,8 @@ impl Frame { Ok(None) } bytecode::Instruction::BuildSet { size, unpack } => { - let elements = self.get_elements(vm, *size, *unpack)?; + let _elements = self.get_elements(vm, *size, *unpack)?; let py_obj = vm.ctx.new_set(); - // TODO: Allow initial population of set with iterable (note: __hash__() of each object being added - // requires access to the VM. (see set_add in objset.rs) self.push_value(py_obj); Ok(None) } diff --git a/vm/src/obj/objset.rs b/vm/src/obj/objset.rs index c16da59cb..a043f4764 100644 --- a/vm/src/obj/objset.rs +++ b/vm/src/obj/objset.rs @@ -3,8 +3,7 @@ */ use super::super::pyobject::{ - IdProtocol, PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, - TypeProtocol, + PyContext, PyFuncArgs, PyObject, PyObjectPayload, PyObjectRef, PyResult, TypeProtocol, }; use super::super::vm::VirtualMachine; use super::objbool; @@ -23,15 +22,6 @@ pub fn get_elements(obj: &PyObjectRef) -> HashMap { } } -pub fn sequence_to_hashmap(iterable: &Vec) -> HashMap { - let mut elements = HashMap::new(); - for item in iterable { - let key = item.get_id(); - elements.insert(key, item.clone()); - } - elements -} - fn perform_action_with_hash(vm: &mut VirtualMachine, elements: &mut HashMap, item: &PyObjectRef, f: &Fn(&mut VirtualMachine, &mut HashMap, BigInt, &PyObjectRef) -> PyResult) -> PyResult { let hash_result: PyResult = vm.call_method(item, "__hash__", vec![]); @@ -50,6 +40,16 @@ fn perform_action_with_hash(vm: &mut VirtualMachine, elements: &mut HashMap, item: &PyObjectRef) -> PyResult +{ + fn insert(vm: &mut VirtualMachine, elements: &mut HashMap, + key: BigInt, value: &PyObjectRef) -> PyResult { + elements.insert(key, value.clone()); + Ok(vm.get_none()) + } + perform_action_with_hash(vm, elements, item, &insert) +} + fn set_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { trace!("set.add called with: {:?}", args); arg_check!( @@ -60,13 +60,7 @@ fn set_add(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { let mut mut_obj = s.borrow_mut(); match mut_obj.payload { - PyObjectPayload::Set {ref mut elements} => { - fn insert_into_set(vm: &mut VirtualMachine, elements: &mut HashMap, - key: BigInt, value: &PyObjectRef) -> PyResult { - elements.insert(key, value.clone()); - Ok(vm.get_none()) - } - perform_action_with_hash(vm, elements, item, &insert_into_set)}, + PyObjectPayload::Set {ref mut elements} => insert_into_set(vm, elements, item), _ => Err(vm.new_type_error("set.add is called with no item".to_string())), } } @@ -82,7 +76,7 @@ fn set_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { match mut_obj.payload { PyObjectPayload::Set {ref mut elements} => { - fn remove_from_set(vm: &mut VirtualMachine, elements: &mut HashMap, + fn remove(vm: &mut VirtualMachine, elements: &mut HashMap, key: BigInt, value: &PyObjectRef) -> PyResult { match elements.remove(&key) { None => { @@ -92,7 +86,7 @@ fn set_remove(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { Some(_) => {Ok(vm.get_none())}, } } - perform_action_with_hash(vm, elements, item, &remove_from_set)}, + perform_action_with_hash(vm, elements, item, &remove)}, _ => Err(vm.new_type_error("set.remove is called with no item".to_string())), } } @@ -110,27 +104,25 @@ fn set_new(vm: &mut VirtualMachine, args: PyFuncArgs) -> PyResult { return Err(vm.new_type_error(format!("{} is not a subtype of set", cls.borrow()))); } -// let elements = match iterable { -// None => HashMap::new(), -// Some(iterable) => { -// let mut elements = HashMap::new(); -// let iterator = objiter::get_iter(vm, iterable)?; -// loop { -// match vm.call_method(&iterator, "__next__", vec![]) { -// Ok(v) => { -// // TODO: should we use the hash function here? -// let key = v.get_id(); -// elements.insert(key, v); -// } -// _ => break, -// } -// } -// elements -// } -// }; + let elements: HashMap = match iterable { + None => HashMap::new(), + Some(iterable) => { + let mut elements = HashMap::new(); + let iterator = objiter::get_iter(vm, iterable)?; + loop { + match vm.call_method(&iterator, "__next__", vec![]) { + Ok(v) => { + insert_into_set(vm, &mut elements, &v).unwrap(); + } + _ => break, + } + } + elements + } + }; Ok(PyObject::new( - PyObjectPayload::Set { elements: HashMap::new() }, + PyObjectPayload::Set { elements: elements }, cls.clone(), )) } diff --git a/vm/src/pyobject.rs b/vm/src/pyobject.rs index e706b15e1..cb73f767d 100644 --- a/vm/src/pyobject.rs +++ b/vm/src/pyobject.rs @@ -441,6 +441,8 @@ impl PyContext { } pub fn new_set(&self) -> PyObjectRef { + // Initialized empty, as calling __hash__ is required for adding each object to the set + // which requires a VM context - this is done in the objset code itself. let elements: HashMap = HashMap::new(); PyObject::new(PyObjectPayload::Set { elements: elements }, self.set_type()) }