I would like to be able to find keys in a Rust BTreeSet that are strictly lower and greater than a specified key.
For example, given the set { "1", "3" }, and the search key is "2" then the answer should be ("1", "3"). In the cases either where either lower or greater value does not exist None should be returned.
I can achieve the result that I am looking for by calling the range() method on the BTreeSet twice.
Is there is a way to do this using a single search, like there is in C++? C++'s std::set has a bi-directional iterator:
// $CXX -std=c++17 less-than.c++ -o less-than && ./less-than
#include <cassert>
#include <optional>
#include <set>
#include <string>
#include <iostream>
using std::optional;
using std::pair;
using std::set;
using std::string;
pair<optional<string>, optional<string>> bounding_box(
const set<string>& space,
const string& point)
{
if (space.empty()) { return {}; }
optional<string> gt_bound;
optional<string> lt_bound;
const auto ge_bound_it = space.lower_bound(point);
if (ge_bound_it != space.end()) {
if (*ge_bound_it == point) {
// lower_bound returned an equal point, use the next one
// if it exists
const auto gt_bound_it = std::next(ge_bound_it, 1);
if (gt_bound_it != space.end()) {
gt_bound = *gt_bound_it;
}
} else {
gt_bound = *ge_bound_it;
}
}
if (ge_bound_it != space.begin()) {
lt_bound = *std::next(ge_bound_it, -1);
}
return {lt_bound, gt_bound};
}
int main() {
{
const auto box = bounding_box({"1", "3"}, "2");
assert(box.first);
assert(*box.first == "1");
assert(box.second);
assert(*box.second == "3");
}
{
const auto box = bounding_box({"1", "3"}, "4");
assert(box.first);
assert(*box.first == "3");
assert(!box.second);
}
{
const auto box = bounding_box({"1", "3"}, "0");
assert(!box.first);
assert(box.second);
assert(*box.second == "1");
}
{
const auto box = bounding_box({"3", "3"}, "3");
assert(!box.first);
assert(!box.second);
}
{
const auto box = bounding_box({"3", "4"}, "3");
assert(!box.first);
assert(box.second);
assert(*box.second == "4");
}
{
const auto box = bounding_box({}, "3");
assert(!box.first);
assert(!box.second);
}
}
The search method is a bit of a hot spot and I wonder if there is an idiomatic way to do this in Rust.
No, there is no way to do this in a single search; you need to call range twice.
There have been discussions about enhancing BTreeMap / BTreeSet to have a "cursor" API. Recently, a pull request was opened to do so, but it was closed because it was deemed that there should be more discussion about how such an API should look and work.
Perhaps you will be the one to spearhead the discussion about such an API?
See also:
How to get the lower bound and upper bound of an element in Rust BTreeSet?
There is not a cursor API in Rust, as said in Shepmaster's answer. You can sometimes simulate it when your iterator implements DoubleEndedIterator with next() and next_back().
However, if I understand well what you are trying to do, you do not need this stuff because a set is ordered. You can write your code by going through each pair and stop when the second item is greater than your "point":
use std::collections::BTreeSet;
fn find_bounds<'a>(set: &'a BTreeSet<&str>, point: &str) -> (Option<&'a str>, Option<&'a str>) {
let mut it = set.iter();
let mut lower = match it.next() {
None => return (None, None),
Some(s) if *s > point => return (None, Some(s)),
Some(s) => s,
};
while let Some(upper) = it.next() {
if *upper > point {
return (Some(lower), Some(*upper));
}
lower = upper;
}
(Some(lower), None)
}
#[test]
fn tests() {
let mut s = BTreeSet::new();
s.insert("a");
s.insert("c");
s.insert("t");
s.insert("g");
assert_eq!(find_bounds(&s, "f"), (Some("c"), Some("g")));
assert_eq!(find_bounds(&s, "z"), (Some("t"), None));
assert_eq!(find_bounds(&s, " "), (None, Some("a")));
}
The code is not well written, but it works.
Related
I'm trying to build an app (macOS, but would be the same for iOS) that creates a number of grids, the outcome of which is to be shown in a second screen. For this, I'm sharing data across these screens, and I'm running into an issue here, I hope someone can help or point me in the right direction. I'll share a simplified version of the code below (working in Xcode 14.0.1)
The code creates a dictionary that can be shown in a grid, on which calculations can be done. The idea is then to add this grid, with some descriptive variables, into another dictionary
The building blocks of the grid are cells
Import Foundation
struct Cell: Comparable, Equatable, Identifiable, Hashable {
static func == (lhs: Cell, rhs: Cell) -> Bool {
lhs.randomVarOne == rhs.randomVarOne
}
var randomVarOne: Double
var randomVarTwo: Bool
// other vars omitted here
var id: Int { randomVarOne }
static func < (lhs: Cell, rhs: Cell) -> Bool {
return lhs.randomVarOne < rhs.randomVarOne
}
}
this is also where there are a bunch of funcs to calculate next neighbor cells in the grid etc
then the grid is defined in a class:
class Info: ObservableObject, Hashable {
static func == (lhs: Info, rhs: Info) -> Bool {
lhs.grid == rhs.grid
}
func hash(into hasher: inout Hasher) {
hasher.combine(grid)
}
#Published var grid = [Cell]()
var arrayTotal = 900
#Published var toBeUsedForTheGridCalculations: Double = 0.0
var toBeUsedToSetTheVarAbove: Double = 0.0
var rowTotalDouble: Double {sqrt(Double(arrayTotal)) }
var rowTotal: Int {
Int(rowTotalDouble) != 0 ? Int(rowTotalDouble) : 10 }
The class includes a func to create and populate the grid with Cells and add these Cells to the grid var. It also includes the formulas to do the calculations on the grid using a user input. The class did not seem to need an initializer.
This is the Scenario struct:
struct Scenario: Comparable, Equatable, Identifiable, Hashable {
static func == (lhs: Scenario, rhs: Scenario) -> Bool {
lhs.scenarioNumber == rhs.scenarioNumber
}
func hash(into hasher: inout Hasher) {
hasher.combine(scenarioNumber)
}
var scenarioNumber: Int
var date: Date
var thisIsOneSnapshot = [Info]()
var id: Int { scenarioNumber }
static func < (lhs: Scenario, rhs: Scenario) -> Bool {
return lhs.scenarioNumber < rhs.scenarioNumber
}
}
added hashable since it uses the Info class as an input.
Then there is the class showing the output overview
class OutputOverview: ObservableObject {
#Published var snapshot = [Scenario]()
// the class includes a formula of how to add the collection of cells (grid) and the additional variables to the snapshot dictionary. Again no initializer was necessary.
Now to go to the ContentView.
struct ContentView: View {
#Environment(\.openURL) var openURL
var scenarioNumberInput: Int = 0
var timeStampAssigned: Date = Date.now
#ObservedObject private var currentGrid: Info = Info()
#ObservedObject private var scenarios: Combinations = Combinations()
var usedForTheCalculations: Double = 0.0
var rows =
[
GridItem(.flexible()),
// whole list of GridItems, I do not know how to calculate these:
// var rows = Array(repeating: GridItem(.flexible()), count: currentGrid.rowTotal)
//gives error "Cannot use instance member 'currentGrid' within property initializer;
// property iunitializers run before 'self' is available
]
var body: some View {
GeometryReader { geometry in
VStack {
ScrollView {
LazyHGrid(rows: rows, spacing: 0) {
ForEach(0..<currentGrid.grid.count, id :\.self) { w in
let temp = currentGrid.grid[w].varThatAffectsFontColor
let temp2 = currentGrid.grid[w].varThatAffectsBackground
Text("\(currentGrid.grid[w].randomVarOne, specifier: "%.2f")")
.frame(width: 25, height: 25)
.border(.black)
.font(.system(size: 7))
.foregroundColor(Color(wordName: temp))
.background(Color(wordName: temp2))
}
}
.padding(.top)
}
VStack{
HStack {
Button("Start") {
}
// then some buttons to do the calculations
Button("Add to collection"){
scenarios.addScenario(numbering: scenarioNumberInput, timeStamp:
Date.now, collection: currentGrid.grid)
} // this should add the newly recalculated grid to the dictionary
Button("Go to Results") {
guard let url = URL(string: "myapp://scenario") else { return }
openURL(url)
} // to go to the screen showing the scenarios
Then the second View, the ScenarioView:
struct ScenarioView: View {
#State var selectedScenario = 1
#ObservedObject private var scenarios: OutputOverview
var pickerNumbers = [ 1, 2, 3, 4 , 5]
// this is to be linked to the number of scenarios completed,this code is not done yet.
var rows =
[
GridItem(.flexible()),
GridItem(.flexible()),
// similar list of GridItems here....
var body: some View {
Form {
Section {
Picker("Select a scenario", selection: $selectedScenario) {
ForEach(pickerNumbers, id: \.self) {
Text("\($0)")
}
}
}
Section {
ScrollView {
if let idx = scenarios.snapshot.firstIndex(where:
{$0.scenarioNumber == selectedScenario}) {
LazyHGrid(rows: rows, spacing: 0) {
ForEach(0..<scenarios.snapshot[idx].thisIsOneSnapshot.count,
id :\.self) { w in
let temp =
scenarios.snapshot[idx].thisIsOneSnapshot[w].varThatAffectsFontColor
let temp2 =
scenarios.snapshot[idx].thisIsOneSnapshot[w].varThatAffectsBackground
Text("\(scenarios.snapshot[idx].thisIsOneSnapshot[w].randomVarOne, specifier: "%.2f")")
.frame(width: 25, height: 25)
.border(.black)
.font(.system(size: 7))
.foregroundColor(Color(wordName: temp))
.background(Color(wordName: temp2))
}
}
}
}
}
}
}
}
Now while the above does not (for the moment..) give me error messages, I am not able to run the PreviewProvider in the second View. The main problem is in #main:
import SwiftUI
#main
struct ThisIsTheNameOfMyApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: ["main"])
WindowGroup("Scenarios") {
ScenarioView()
// error messages here: 'ScenarioView' initializer is inaccessible due to "private"
// protection level - I don't know what is set to private in ScenarioView that could
// cause this
// second error message: missing argument for parameter 'scenarios' in call
}
.handlesExternalEvents(matching: ["scenario"])
}
}
I am at a loss on how to solve these 2 error messages and would be very grateful for any tips or guidance. Apologies if this question is very long, I scanned many other forum questions and could not find any good answers.
I have tried adding pro forma data in #main as follows
#main
struct FloodModelScenarioViewerApp: App {
#State var scenarios = Scenario(scenarioNumber: 1, date: Date.now)
var body: some Scene {
WindowGroup {
ContentView()
}
.handlesExternalEvents(matching: ["main"])
WindowGroup("Scenarios") {
ScenarioView(scenarios: scenarios)
}
.handlesExternalEvents(matching: ["scenario"])
}
}
This still gives 2 error messages:
same issue with regards to ScenarioView initialiser being inaccessible due to being 'private'
Cannot convert value of type 'Scenario' to expected argument type 'OutputOverview'
Just remove the private from
#ObservedObject private var scenarios: OutputOverview
The value is coming from he parent so the parent needs access. So put
#StateObject private var scenarios: OutputOverview = .init()
in FloodModelScenarioViewerApp
#StateObject is for initializing ObservableObjects and #ObservedObject is for passing them around.
I don't know if your code will work after you read this question, and that's because there are many things to correct, but you can start with these:
In Cell, you shouldn't use an id that is a variable, this may cause inconsistent behavior. Use something like:
let id = UUID()
When you initialize ContentView, you can't use currentGrid inside a variable because currentGrid will not be available before all variables are initialized. Meaning, you are trying to initialize rows before currentGrid actually exists. You can try using the .onAppear modifier:
var rows = [GridItem]()
var body: some View {
GeometryReader { geometry in
// ... view code in here
}
.onAppear {
var rows = Array(repeating: GridItem(.flexible()), count: currentGrid.rowTotal)
}
}
This creates the view and, before showing it, the grid is set to its proper value.
The message 'ScenarioView' initializer is inaccessible due to "private" protection level seems clear: you must provide a value to to the variable scenarios (it doesn't have a default value) but it's marked as private. Remove private.
#ObservedObject var scenarios: OutputOverview
Then, remember to pass a value of type OutputOverview for the variable when you call the view:
ScenarioView(scenarios: aVariableOfTypeOutputOverview)
The type mismatch error you get inside the #main code is also clear - you have defined a variable of type Scenario:
#State var scenarios = Scenario(scenarioNumber: 1, date: Date.now)
but ScenarioView requires another type:
#ObservedObject private var scenarios: OutputOverview
One of them needs change for your code to work.
I was unsure if I should post this here or in code review.
Code review seems to have only functioning code.
So I've a multitude of problems I don't really understand.
(I’m a noob) full code can be found here: https://github.com/NicTanghe/winder/blob/main/src/main.rs
main problem is here:
let temp = location_loc1.parent().unwrap();
location_loc1.push(&temp);
I’ve tried various things to get around problems with borrowing as mutable or as reference,
and I can’t seem to get it to work.
I just get a different set of errors with everything I try.
Furthermore, I'm sorry if this is a duplicate, but looking for separate solutions to the errors just gave me a different error. In a circle.
Full function
async fn print_events(mut selector_loc1:i8, location_loc1: PathBuf) {
let mut reader = EventStream::new();
loop {
//let delay = Delay::new(Duration::from_millis(1_000)).fuse();
let mut event = reader.next().fuse();
select! {
// _ = delay => {
// print!("{esc}[2J{esc}[1;1H{}", esc = 27 as char,);
// },
maybe_event = event => {
match maybe_event {
Some(Ok(event)) => {
//println!("Event::{:?}\r", event);
// if event == Event::Mouse(MouseEvent::Up("Left").into()) {
// println!("Cursor position: {:?}\r", position());
// }
print!("{esc}[2J{esc}[1;1H{}", esc = 27 as char,);
if event == Event::Key(KeyCode::Char('k').into()) {
if selector_loc1 > 0 {
selector_loc1 -= 1;
};
//println!("go down");
//println!("{}",selected)
} else if event == Event::Key(KeyCode::Char('j').into()) {
selector_loc1 += 1;
//println!("go up");
//println!("{}",selected)
} else if event == Event::Key(KeyCode::Char('h').into()) {
//-----------------------------------------
//-------------BackLogic-------------------
//-----------------------------------------
let temp = location_loc1.parent().unwrap();
location_loc1.push(&temp);
//------------------------------------------
//------------------------------------------
} else if event == Event::Key(KeyCode::Char('l').into()) {
//go to next dir
} if event == Event::Key(KeyCode::Esc.into()) {
break;
}
printtype(location_loc1,selector_loc1);
}
Some(Err(e)) => println!("Error: {:?}\r", e),
None => break,
}
}
};
}
}
also, it seems using
use async_std::path::{Path, PathBuf};
makes the rust not recognize unwrap() function → how would I use using ?
There are two problems with your code.
Your PathBuf is immutable. It's not possible to modify immutable objects, unless they support interior mutability. PathBuf does not. Therefore you have to make your variable mutable. You can either add mut in front of it like that:
async fn print_events(mut selector_loc1:i8, mut location_loc1: PathBuf) {
Or you can re-bind it:
let mut location_loc1 = location_loc1;
You cannot have borrow it both mutable and immutably - the mutable borrows are exclusive! Given that the method .parent() borrows the buffer, you have to create a temporary owned value:
// the PathBuf instance
let mut path = PathBuf::from("root/parent/child");
// notice the .map(|p| p.to_owned()) method - it helps us avoid the immutable borrow
let parent = path.parent().map(|p| p.to_owned()).unwrap();
// now it's fine to modify it, as it's not borrowed
path.push(parent);
Your second question:
also, it seems using use async_std::path::{Path, PathBuf}; makes the rust not recognize unwrap() function → how would I use using ?
The async-std version is just a wrapper over std's PathBuf. It just delegates to the standard implementation, so it should not behave differently
// copied from async-std's PathBuf implementation
pub struct PathBuf {
inner: std::path::PathBuf,
}
Coming from another language I'm a little confused on how to do some basic stuff in Rust without breaking memory safety.
I'm trying to get references to a pair of elements stored in a Vec. Assume the elements stored in the Vec are large and I do not want to copy them:
struct Element {
key: u64,
data: SomeHugeType
}
In other languages (e.g. C++), I would just create two null pointers or something and loop over the vec like so:
const Element *ele1, *ele2;
ele1 = nullptr;
ele2 = nullptr;
for (auto const &ele : elements) {
if (ele.key == key1) { ele1 = ele; }
if (ele.key == key2) { ele2 = ele; }
if (ele1 != nullptr && ele2 != nullptr) { break; }
}
if (ele1 == nullptr || ele2 == nullptr) { /* uh oh */}
But as far as I know I cannot do this in rust because I cannot have a reference to nothing (nullptr). I cannot borrow an element before I know which element I need to borrow.
How can I initialize some variable ele1 and ele2 before I find the actual elements they should reference in the Vec?
To elaborate on Sebastian's answer, you can use None and Some(element) instead of nullptrs in C++:
type SomeHugeType = String;
struct Element {
key: u64,
data: SomeHugeType,
}
fn get_two_elems(elems: &Vec<Element>, key1: u64, key2: u64) -> Option<(&Element, &Element)> {
let (mut elem1, mut elem2) = (None, None);
for elem in elems {
if elem.key == key1 {
elem1 = Some(elem);
} else if elem.key == key2 {
elem2 = Some(elem)
}
if elem1.is_some() && elem2.is_some() {
break;
}
}
if let (Some(elem1), Some(elem2)) = (elem1, elem2) {
Some((elem1, elem2))
} else {
None
}
}
You can have a reference to nothing. It's just the type Option<T&>
On the Flowtype "Try" site
// #flow
type One = {type: "One"};
type Two = {type: "Two"};
type Node = One | Two;
class Foo<N: Node> {
node: N;
constructor(n: N) {
this.node = n;
}
}
const fooNode: Foo<Node> = new Foo({type: "One"});
if (fooNode.node.type === "One") {
const fooOne: Foo<One> = fooNode;
}
the if type check is not enough to refine the type, if I understand right, because the type is not guaranteed to be constant.
Since I want to avoid the possibility of this being an X/Y problem, the usecase I'm playing with at the moment is searching from a given node with a .find method that would return the refined type, e.g. using
parent(): Foo<N> | null {
// ...
return null;
}
find<U: Node>(callback: (foo: Foo<N>) => Foo<U> | null): Foo<U> | null {
let p = this;
do {
const result = callback(p);
if (result) return result;
p = p.parent();
} while (p);
return null;
}
with
const f: Foo<Node> = new Foo({type: "One"});
const result: Foo<Two>|null = f.find((p) => p.node.type === "Two" ? p : null);
which would allow me to return the refined type at the while searching.
The problem is with the type annotation on this line:
const fooNode: Foo<Node> = new Foo({type: "One"});
By explicitly using Foo<Node> you're preventing the refinement from happening. You can use Foo<*> to make the inference work correctly.
Here's an example:
https://flowtype.org/try/#0PTAEAEDMBsHsHcBQiAuBPADgU1AeQHY4C8oA3qOtgFygBEBWtoAvgNyqY4Aq8soJ5Slhq0esJmw7ZQAOVgATYnkKgAPqDHtEAY2gBDAM4HQAMViwAPDJpzFAPjKJQofAuGytz7bHwGUAJwBXbRRYfwAKfBsASkdnZxQACwBLAwA6V0V+F3ZnZkR85G9fFFBIc1t3M0sAKgcSQnhTc3DSIREGWmZo9nDy2EqaaosGOx7EPoq3IfMLMTHWUBBQLH9-MKA
There are two problems. Foo is invariant, so you will never be able to refine it: it doesn't have any known subtypes other than itself.
On the other hand, even if Foo was covariant, it wouldn't work. You simply can't refine a generic class.
The only practical option is to unwrap, refine, and wrap again.
I am trying to convert some Objective C code provided in one of Apple's code examples here: https://developer.apple.com/library/mac/samplecode/avsubtitleswriterOSX/Listings/avsubtitleswriter_SubtitlesTextReader_m.html
The result I have come up with thus far is as follows:
func copySampleBuffer() -> CMSampleBuffer? {
var textLength : Int = 0
var sampleSize : Int = 0
if (text != nil) {
textLength = text!.characters.count
sampleSize = text!.lengthOfBytesUsingEncoding(NSUTF16StringEncoding)
}
var sampleData = [UInt8]()
// Append text length
sampleData.append(UInt16(textLength).hiByte())
sampleData.append(UInt16(textLength).loByte())
// Append the text
for char in (text?.utf16)! {
sampleData.append(char.bigEndian.hiByte())
sampleData.append(char.bigEndian.loByte())
}
if (self.forced) {
// TODO
}
let samplePtr = UnsafeMutablePointer<[UInt8]>.alloc(1)
samplePtr.memory = sampleData
var sampleTiming = CMSampleTimingInfo()
sampleTiming.duration = self.timeRange.duration;
sampleTiming.presentationTimeStamp = self.timeRange.start;
sampleTiming.decodeTimeStamp = kCMTimeInvalid;
let formatDescription = copyFormatDescription()
let dataBufferUMP = UnsafeMutablePointer<Optional<CMBlockBuffer>>.alloc(1)
CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, samplePtr, sampleSize, kCFAllocatorMalloc, nil, 0, sampleSize, 0, dataBufferUMP);
let sampleBufferUMP = UnsafeMutablePointer<Optional<CMSampleBuffer>>.alloc(1)
CMSampleBufferCreate(kCFAllocatorDefault, dataBufferUMP.memory, true, nil, nil, formatDescription, 1, 1, &sampleTiming, 1, &sampleSize, sampleBufferUMP);
let sampleBuffer = sampleBufferUMP.memory
sampleBufferUMP.destroy()
sampleBufferUMP.dealloc(1)
dataBufferUMP.destroy()
dataBufferUMP.dealloc(1)
samplePtr.destroy()
//Crash if I call dealloc here
//Error is: error for object 0x10071e400: pointer being freed was not allocated
//samplePtr.dealloc(1)
return sampleBuffer;
}
I would like to avoid the "Unsafe*" types where possible, though I am not sure it is possible here. I also looked at using a struct and then somehow seeing to pack it somehow, but example I see seem to be based of sizeof, which uses the size of the definition, rather than the current size of the structure. This would have been the structure I would have used:
struct SubtitleAtom {
var length : UInt16
var text : [UInt16]
var forced : Bool?
}
Any advice on most suitable Swift 2 code for this function would be appreciated.
so, at first, you code use this pattern
class C { deinit { print("I got deinit'd!") } }
struct S { var objectRef:AnyObject? }
func foo() {
let ptr = UnsafeMutablePointer<S>.alloc(1)
let o = C()
let fancy = S(objectRef: o)
ptr.memory = fancy
ptr.destroy() //deinit runs here!
ptr.dealloc(1) //don't leak memory
}
// soon or later this code should crash :-)
(1..<1000).forEach{ i in
foo()
print(i)
}
Try it in a playground and most likely it crash :-). What's wrong with it? The trouble is your unbalanced retain / release cycles. How to write the same in the safe manner? You removed dealloc part. But try to do it in my snippet and see the result. The code crash again :-). The only safe way is to properly initialize and de-ininitialize (destroy) the underlying ptr's Memory as you can see in next snippet
class C { deinit { print("I got deinit'd!") } }
struct S { var objectRef:AnyObject? }
func foo() {
let ptr = UnsafeMutablePointer<S>.alloc(1)
let o = C()
let fancy = S(objectRef: o)
ptr.initialize(fancy)
ptr.destroy()
ptr.dealloc(1)
}
(1..<1000).forEach{ i in
foo()
print(i)
}
Now the code is executed as expected and all retain / release cycles are balanced.