-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
FlaggedStorage #93
FlaggedStorage #93
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if this has already been discussed (and I forgot), but I feel that comps.get_mut(entity)
is something we can do better at
src/storage.rs
Outdated
/// // Instead do something like: | ||
/// for (entity, comp) in (&entities, &comps.check()).iter() { | ||
/// if true { // check whether you should modify this component or not. | ||
/// let mut comp = comps.get_mut(entity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, we should be able to make this nicer. Asking for get_mut
on an entity that we are currently iterating on would be slower than just giving the value right away. Perhaps, the check()
could iterate over some nice wrapper aka std::hashmap::Entry
, so that actually accessing the data becomes straightforward (in terms of performance)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm assuming the main problem is just that calling get_mut
means it is checking again whether the entity has the component, even though we already know?
src/storage.rs
Outdated
|
||
impl<C: Component, T: UnprotectedStorage<C>> TrackedStorage<C, T> { | ||
/// All components will be cleared of being flagged. | ||
pub fn clear(&mut self) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
needs to be renamed to clear_flags
Also, this runs into the same problem as the |
Yes.
I don't think |
src/storage.rs
Outdated
} | ||
unsafe fn get_mut(&mut self, id: Index) -> &mut C { | ||
// calling `.iter()` on a mutable reference to the storage will flag everything | ||
self.mask.add(id); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I imagine that such a TrackedStorage
would be best used in the following way:
// pos is a component storage with a `TrackedStorage`
for (vel, pos) in (&vel, &mut pos).join() {
*pos += vel * delta_time;
}
In another system:
for (pos_handle, matrix) in (pos.check(), &mut mvp).join() {
if pos.flagged(pos_handle) {
// Recalc
} else {
// Use cached version
}
}
It's inconvenient to do whatever checks and often too complicated, instead we might want a method on UnprotectedStorage
which is called after every iterated component, where we check for equality. This would also solve the lifetime problem of a guard.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would a cached version be? Wouldn't the matrix just stay the same? Although good idea of using Entry<'a>
for TrackedStorage
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Aceeri Yeah, the matrix would stay just the same. The comment above is just not very clear about that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great, thanks!
/// | ||
/// **Note: Never use `.iter()` on a mutable component storage that uses this.** | ||
/// | ||
///# Example Usage: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice docs!
In case you don't want to add or change anything, I'd say you can merge it after squashing. bors delegate=Aceeri Not sure if bors knows "delegate", otherwise I'll merge it. |
Documentation about common pitfalls and usage. Join implementations for only iterating over flagged components.
bors r+ |
🔒 Permission denied |
src/storage/storages.rs
Outdated
/// } | ||
///# fn main() { } | ||
/// ``` | ||
pub struct TrackedStorage<C, T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just had an idea:
Given that both this storage and ChangeStorage
track the mutation of their components, maybe we should rename this one to FlaggedStorage
?
Nice we finally have a bors r+ |
93: FlaggedStorage r=torkleyy A basic implementation for a `TrackedStorage` (#89). This version of the `TrackedStorage` does not implement a way to compare the past version and the modifies version of the components. Usage requires unwrapping the storage to the base `TrackedStorage` which implements `Join` for flagged components. ### Alternative design choices: **Implement `TrackedStorage` similar to how `MaskedStorage` works.** _Pros:_ - Would make it possible to have the `Join` of the storage only work on the flagged components without calling any additional methods. - Might open up a path for a generic storage wrapper like `UnprotectedStorage` but instead as a container for how the `Join` gets the components necessary for the loop (this could be interesting since it would allow for different methods other than bitsets, but would also be pretty hard to get right). _Cons:_ - Difficult to get all the components instead of just the flagged ones as there is no current way to directly get access to the container storage. - Might be unintuitive at a glance as you would expect to get all the components when joining the storage. **Compare modifications for more accurate flags** _Pros:_ - Removes a large concern for if the user iterates over a mutable tracked storage. _Cons:_ - Performance benefits of the tracked storage decreases. - Difficult to implement. Requires a way to directly compare the new "modified" version with the past version.
Build succeeded |
A basic implementation for a
TrackedStorage
(#89).This version of the
TrackedStorage
does not implement a way to compare the past version and the modifies version of the components. Usage requires unwrapping the storage to the baseTrackedStorage
which implementsJoin
for flagged components.Alternative design choices:
Implement
TrackedStorage
similar to howMaskedStorage
works.Pros:
Join
of the storage only work on the flagged components without calling any additional methods.UnprotectedStorage
but instead as a container for how theJoin
gets the components necessary for the loop (this could be interesting since it would allow for different methods other than bitsets, but would also be pretty hard to get right).Cons:
Compare modifications for more accurate flags
Pros:
Cons: