Compile Time HashMap in Zig - hashmap

Take for example the Rust library lazy_static's example:
use lazy_static::lazy_static;
use std::collections::HashMap;
lazy_static! {
static ref HASHMAP: HashMap<u32, &'static str> = {
let mut m = HashMap::new();
m.insert(0, "foo");
m.insert(1, "bar");
m.insert(2, "baz");
m
};
static ref COUNT: usize = HASHMAP.len();
static ref NUMBER: u32 = times_two(21);
}
How might this be done in Zig?
I have tried this which is the only thing that makes sense to me:
const std = #import("std");
pub fn main() void {
comptime var h = std.StringHashMap(i32).init(std.testing.allocator);
h.put("hi", 5) catch {};
std.debug.print("{}", .{h});
}
but this segfaults.
Is it even possible to do this in Zig?

It seems (thanks to this Reddit post) that this is implemented in the standard library
and can be used via std.ComptimeStringMap
This however does not seem to support any dynamic insertion as there is no insert method.

Related

Create a vector with macro iterator syntax

How can I create a new vector with the iterator Rust macro syntax?
I am trying this:
unsafe {
MUT_STATIC_VAR = vec![
#(#my_outher_vector_data)*,
];
}
Full explanation: I am trying to reasign data that I write in one mut static var of type: Vec when the macro it's spanded at compile time. When I try to retrieve the data at runtime, the global it's empty, so I am rewiring the data that I want in main().
Recap. I am just want to assign the content of one vector to another, but neither array or Vec<T> implements ToTokens.
Compiler error:
`main` function not found in crate `my_crate`
Thanks
To initialize the content, Iterators are able to use macro #(#...)*, syntax.
let other_as_iter = my_outher_vector_data.iter();
quote {
unsafe {
MUT_STATIC_VAR = vec![
#(#other_as_iter)*,
];
}
}
I think lazy_static should do the job:
#[macro_use]
extern crate lazy_static;
use std::sync::Mutex;
lazy_static! {
static ref MUT_STATIC_VAR: Mutex<Vec<String>> = Mutex::new(vec![]);
}
fn other_vec(v: Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.as_slice());
}
fn main() {
other_vec(vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or draining the other vec after initializing MUT_STATIC_VAR:
fn other_vec(v: &mut Vec<String>) {
let mut r = MUT_STATIC_VAR.lock().unwrap();
r.extend_from_slice(v.drain(..).as_slice());
}
fn main() {
other_vec(&mut vec!["dog".to_string(), "cat".to_string(), "mouse".to_string()]);
}
…or my_other_vector_data wrapped in other_vec! macro:
Playground
macro_rules! other_vec {
() => {
vec!["dog", "cat", "mouse"] // my_other_vector_data here
};
}

How do I remove `MutexGuard` around a value?

I'm trying to use ndarray as an asynchronous process to do linear algebra and such.
I used Rust's tokio and ndarray to create the following code.
use std::sync::{Arc, Mutex};
use ndarray::prelude::*;
use futures::future::join_all;
fn print_type_of<T>(_: &T) {
println!("{}", std::any::type_name::<T>())
}
#[tokio::main]
async fn main() {
let db = Arc::new(Mutex::new(array![0,0,0,0,0,0,0,0]));
let mut handels = vec![];
for i in 0..8 {
let db = db.clone();
let unchange_array = unchange_array.clone();
handels.push(tokio::spawn(async move{
print(i, db).await;
}));
}
join_all(handels).await;
let array = Arc::try_unwrap(db).unwrap();
let array = array.lock().unwrap();
print_type_of(&array); // -> std::sync::mutex::MutexGuard<ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<u32>, ndarray::dimension::dim::Dim<[usize; 1]>>>
}
async fn print(i: u32, db: Arc<Mutex<Array1<u32>>>) {
let unchange = unchange.to_owned();
let mut tmp = 0;
// time-consuming process
for k in 0..100000000 {
tmp = k;
}
tmp += i;
let mut db = db.lock().unwrap();
db.fill(i);
println!("{:?}", unchange);
print_type_of(&db);
}
I would like to change the data std::sync::mutex::MutexGuard<ndarray::ArrayBase<OwnedRepr<u32>, Dim<[usize; 1]>>>
to ndarray::ArrayBase<OwnedRepr<u32>, Dim<[usize; 1]>>.
How can I do this?
You can't. That's the whole point of MutexGuard: if you could take the data out of the MutexGuard, then you would be able to make a reference that can be accessed without locking the mutex, defeating the whole purpose of having a mutex in the first place.
Depending on what you really want to do, one of the following solutions might apply to you:
Most of the time, you don't need to take the data out of the mutex: MutexGuard<T> implements Deref<Target=T> and DerefMut<Target=T>, so you can use the MutexGuard everywhere you would use a &T or a &mut T. Note that if you change your code to call print_type_of(&*array) instead of print_type_of(&array), it will print the inner type.
If you really need to, you can take the data out of the Mutex itself (but not the MutexGuard) with into_inner, which consumes the mutex, ensuring that no one else can ever access it:
let array = Arc::try_unwrap(db).unwrap();
let array = array.into_inner().unwrap();
print_type_of(&array); // -> ndarray::ArrayBase<ndarray::data_repr::OwnedRepr<u32>, ndarray::dimension::dim::Dim<[usize; 1]>>

Idiomatic Rust method for handling references to a buffer

I would like to be able to construct objects that contain immutable references to a mutable buffer object. The following code does not work but illustrates my use case, is there an idiomatic Rust method for handling this?
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source;
let parser = Parser { buffer };
// How can I legally change source?
source.push_str(" Pan");
println!("{:?}", parser);
}
The golden rule of the rust borrow checker is: Only one writer OR multiple readers can access a resource at a time. This ensures that algorithms are safe to run in multiple threads.
You breach this rule here:
#[derive(Debug)]
struct Parser<'a> {
buffer: &'a String
}
fn main() {
// mutable access begins here
let mut source = String::from("Peter");
// immutable access begins here
let buffer = &source;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{:?}", parser);
// Both immutable and mutable access end here
}
If you are sure that your program doesn't actively access resources at the same time mutably and immutably, you can move the check from compile time to run time by wrapping your resource in a RefCell:
use std::cell::RefCell;
use std::rc::Rc;
#[derive(Debug)]
struct Parser {
buffer: Rc<RefCell<String>>
}
fn main() {
let source = Rc::new(RefCell::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.borrow_mut().push_str(" Pan");
println!("{:?}", parser);
}
If you plan on passing your resource around threads, you can use an RwLock to block the thread until the resource is available:
use std::sync::{RwLock, Arc};
#[derive(Debug)]
struct Parser {
buffer: Arc<RwLock<String>>
}
fn main() {
let source = Arc::new(RwLock::new(String::from("Peter")));
let parser = Parser { buffer: source.clone() };
source.write().unwrap().push_str(" Pan");
println!("{:?}", parser);
}
On another note, you should prefer &str over &String
It's hard to tell what exactly you want to achieve by mutating the source; I would assume you don't want it to happen while the parser is doing its work? You can always try (depending on your specific use case) to separate the immutable from the mutable with an extra scope:
fn main() {
let mut source = String::from("Peter");
{
let buffer = &source;
let parser = Parser { buffer };
println!("{:?}", parser);
}
source.push_str(" Pan");
}
If you don't want to use RefCell, unsafe (or to simply keep a mutable reference to source in Parser and use that), I'm afraid it doesn't get better than plain refactoring.
To elaborate on how this can be done unsafely, what you've described can be achieved by using a raw const pointer to avoid the borrowing rules, which of course is inherently unsafe, as the very concept of what you've described is pretty unsafe. There are ways to make it safer though, should you choose this path. But I would probably default to using an Arc<RwLock> or Arc<Mutex> should safety be important.
use std::fmt::{self, Display};
#[derive(Debug)]
struct Parser {
buffer: *const String
}
impl Display for Parser {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let buffer = unsafe { &*self.buffer };
write!(f, "{}", buffer)
}
}
fn main() {
let mut source = String::from("Peter");
let buffer = &source as *const String;
let parser = Parser { buffer };
source.push_str(" Pan");
println!("{}", parser);
}

How can I figure out why a call to LLVMTargetMachineEmitToFile fails when called using llvm-sys?

extern crate llvm_sys;
use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;
pub fn emit(module: LLVMModuleRef) {
unsafe {
use llvm_sys::target::*;
use llvm_sys::target_machine::*;
let triple = LLVMGetDefaultTargetTriple();
LLVM_InitializeNativeTarget();
let target = LLVMGetFirstTarget();
let cpu = "x86-64\0".as_ptr() as *const i8;
let feature = "\0".as_ptr() as *const i8;
let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
let code_model = LLVMCodeModel::LLVMCodeModelDefault;
let target_machine = LLVMCreateTargetMachine(target, triple, cpu, feature, opt_level, reloc_mode, code_model);
let file_type = LLVMCodeGenFileType::LLVMObjectFile;
LLVMTargetMachineEmitToFile(target_machine, module, "/Users/andyshiue/Desktop/main.o\0".as_ptr() as *mut i8, file_type, ["Cannot generate file.\0".as_ptr()].as_mut_ptr() as *mut *mut i8);
}
}
I'm writing a toy compiler and I want to generate object files, but the file LLVM outputs is empty.
I found that LLVMTargetMachineEmitToFile returns 1, which means something I'm doing is wrong, but what am I doing wrong?
It would be better if I can know how I can know what is wrong. Is there any way I can get some error message? I don't have any experience in C/C++.
As commenters have already said, to do what you want to do (write a compiler using LLVM), you are going to need to be able to read (and probably write) at the very least C and maybe C++.
Even though you are compiling code with the Rust compiler, you aren't really writing any Rust yet. Your entire program is wrapped in unsafe blocks because you are calling the C functions exposed by LLVM (which is written in C++). This may be why some commenters are asking if you have gotten your code to work in C first.
As in your other question, you are still calling the LLVM methods incorrectly. In this case, review the documentation for LLVMTargetMachineEmitToFile:
LLVMBool LLVMTargetMachineEmitToFile(LLVMTargetMachineRef T,
LLVMModuleRef M,
char *Filename,
LLVMCodeGenFileType codegen,
char **ErrorMessage)
Returns any error in ErrorMessage. Use LLVMDisposeMessage to dispose the message.
The method itself will tell you what is wrong, but you have to give it a place to store the error message. You should not provide an error string to it. I'm pretty sure that the current code is likely to generate some exciting memory errors when it tries to write to the string literal.
If I rewrite your code to use the error message:
extern crate llvm_sys;
use llvm_sys::*;
use llvm_sys::prelude::*;
use llvm_sys::core::*;
use std::ptr;
use std::ffi::{CStr, CString};
pub fn emit(module: LLVMModuleRef) {
let cpu = CString::new("x86-64").expect("invalid cpu");
let feature = CString::new("").expect("invalid feature");
let output_file = CString::new("/tmp/output.o").expect("invalid file");
unsafe {
use llvm_sys::target::*;
use llvm_sys::target_machine::*;
let triple = LLVMGetDefaultTargetTriple();
LLVM_InitializeNativeTarget();
let target = LLVMGetFirstTarget();
let opt_level = LLVMCodeGenOptLevel::LLVMCodeGenLevelNone;
let reloc_mode = LLVMRelocMode::LLVMRelocDefault;
let code_model = LLVMCodeModel::LLVMCodeModelDefault;
let target_machine = LLVMCreateTargetMachine(target, triple, cpu.as_ptr(), feature.as_ptr(), opt_level, reloc_mode, code_model);
let file_type = LLVMCodeGenFileType::LLVMObjectFile;
let mut error_str = ptr::null_mut();
let res = LLVMTargetMachineEmitToFile(target_machine, module, output_file.as_ptr() as *mut i8, file_type, &mut error_str);
if res == 1 {
let x = CStr::from_ptr(error_str);
panic!("It failed! {:?}", x);
// TODO: Use LLVMDisposeMessage here
}
}
}
fn main() {
unsafe {
let module = LLVMModuleCreateWithName("Main\0".as_ptr() as *const i8);
emit(module);
}
}
TargetMachine can't emit a file of this type
So that's your problem.
Rust-wise, you may want to wrap up the work needed to handle the silly LLVMBool so you can reuse it. One way would be:
fn llvm_bool<F>(f: F) -> Result<(), String>
where F: FnOnce(&mut *mut i8) -> i32
{
let mut error_str = ptr::null_mut();
let res = f(&mut error_str);
if res == 1 {
let err = unsafe { CStr::from_ptr(error_str) };
Err(err.to_string_lossy().into_owned())
//LLVMDisposeMessage(error_str);
} else {
Ok(())
}
}
// later
llvm_bool(|error_str| LLVMTargetMachineEmitToFile(target_machine, module, output_file.as_ptr() as *mut i8, file_type, error_str)).expect("Couldn't output");

Thread-safe mutable non-owning pointer in Rust?

I'm trying to parallelize an algorithm I have. This is a sketch of how I would write it in C++:
void thread_func(std::vector<int>& results, int threadid) {
results[threadid] = threadid;
}
std::vector<int> foo() {
std::vector<int> results(4);
for(int i = 0; i < 4; i++)
{
spawn_thread(thread_func, results, i);
}
join_threads();
return results;
}
The point here is that each thread has a reference to a shared, mutable object that it does not own. It seems like this is difficult to do in Rust. Should I try to cobble it together in terms of (and I'm guessing here) Mutex, Cell and &mut, or is there a better pattern I should follow?
The proper way is to use Arc<Mutex<...>> or, for example, Arc<RWLock<...>>. Arc is a shared ownership-based concurrency-safe pointer to immutable data, and Mutex/RWLock introduce synchronized internal mutability. Your code then would look like this:
use std::sync::{Arc, Mutex};
use std::thread;
fn thread_func(results: Arc<Mutex<Vec<i32>>>, thread_id: i32) {
let mut results = results.lock().unwrap();
results[thread_id as usize] = thread_id;
}
fn foo() -> Arc<Mutex<Vec<i32>>> {
let results = Arc::new(Mutex::new(vec![0; 4]));
let guards: Vec<_> = (0..4).map(|i| {
let results = results.clone();
thread::spawn(move || thread_func(results, i))
}).collect();
for guard in guards {
guard.join();
}
results
}
This unfortunately requires you to return Arc<Mutex<Vec<i32>>> from the function because there is no way to "unwrap" the value. An alternative is to clone the vector before returning.
However, using a crate like scoped_threadpool (whose approach could only be recently made sound; something like it will probably make into the standard library instead of the now deprecated thread::scoped() function, which is unsafe) it can be done in a much nicer way:
extern crate scoped_threadpool;
use scoped_threadpool::Pool;
fn thread_func(result: &mut i32, thread_id: i32) {
*result = thread_id;
}
fn foo() -> Vec<i32> {
let results = vec![0; 4];
let mut pool = Pool::new(4);
pool.scoped(|scope| {
for (i, e) in results.iter_mut().enumerate() {
scope.execute(move || thread_func(e, i as i32));
}
});
results
}
If your thread_func needs to access the whole vector, however, you can't get away without synchronization, so you would need a Mutex, and you would still get the unwrapping problem:
extern crate scoped_threadpool;
use std::sync::Mutex;
use scoped_threadpool::Pool;
fn thread_func(results: &Mutex<Vec<u32>>, thread_id: i32) {
let mut results = results.lock().unwrap();
result[thread_id as usize] = thread_id;
}
fn foo() -> Vec<i32> {
let results = Mutex::new(vec![0; 4]);
let mut pool = Pool::new(4);
pool.scoped(|scope| {
for i in 0..4 {
scope.execute(move || thread_func(&results, i));
}
});
results.lock().unwrap().clone()
}
But at least you don't need any Arcs here. Also execute() method is unsafe if you use stable compiler because it does not have a corresponding fix to make it safe. It is safe on all compiler versions greater than 1.4.0, according to its build script.

Resources