Skip to content

Commit

Permalink
Absorbed AccessSet implementation into TypeAccess.
Browse files Browse the repository at this point in the history
  • Loading branch information
Ratysz committed Dec 29, 2020
1 parent 8fbe2a7 commit c4e8261
Showing 1 changed file with 68 additions and 109 deletions.
177 changes: 68 additions & 109 deletions crates/bevy_ecs/src/core/access.rs
Original file line number Diff line number Diff line change
Expand Up @@ -196,87 +196,6 @@ impl QueryAccess {
}
}

// TODO consider ditching, see CondensedTypeAccess for comparison
#[derive(Debug, Eq, PartialEq, Clone)]
enum AccessSet<T: Hash + Eq + PartialEq> {
All,
Some(HashSet<T>),
}

impl<T: Hash + Eq + PartialEq> Default for AccessSet<T> {
fn default() -> Self {
Self::Some(Default::default())
}
}

impl<T: Hash + Eq + PartialEq + Copy> AccessSet<T> {
fn is_disjoint(&self, other: &AccessSet<T>) -> bool {
if let (AccessSet::Some(set), AccessSet::Some(other)) = (self, other) {
set.is_disjoint(other)
} else {
false
}
}

fn extend(&mut self, other: &AccessSet<T>) {
match self {
AccessSet::All => (),
AccessSet::Some(set) => match other {
AccessSet::All => *self = AccessSet::All,
AccessSet::Some(other) => set.extend(other),
},
}
}

fn insert(&mut self, item: T) {
match self {
AccessSet::All => (),
AccessSet::Some(set) => {
set.insert(item);
}
}
}

fn clear(&mut self) {
match self {
// If a system had full access before, it'll have full access next time either way.
AccessSet::All => (),
AccessSet::Some(set) => set.clear(),
}
}

fn contains(&self, item: &T) -> bool {
match self {
AccessSet::All => true,
AccessSet::Some(set) => set.contains(item),
}
}

fn find_conflict<'a>(&'a self, other: &'a AccessSet<T>) -> AccessConflict<'a, T> {
match (self, other) {
(AccessSet::Some(set), AccessSet::Some(other)) => {
if let Some(intersection) = set.intersection(other).next() {
return AccessConflict::Element(intersection);
}
}
(AccessSet::Some(set), AccessSet::All) | (AccessSet::All, AccessSet::Some(set)) => {
if let Some(first) = set.iter().next() {
return AccessConflict::Element(first);
}
}
(AccessSet::All, AccessSet::All) => return AccessConflict::All,
}
AccessConflict::None
}

fn distinct_iterator(&self) -> Option<impl Iterator<Item = &T>> {
match self {
AccessSet::All => None,
AccessSet::Some(set) => Some(set.iter()),
}
}
}

pub enum AccessConflict<'a, T> {
None,
Element(&'a T),
Expand All @@ -286,17 +205,19 @@ pub enum AccessConflict<'a, T> {
/// Provides information about the types a [System] reads and writes
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct TypeAccess<T: Hash + Eq + PartialEq> {
reads_and_writes: AccessSet<T>,
writes: AccessSet<T>,
reads: AccessSet<T>,
reads_all: bool,
writes_all: bool,
reads_and_writes: HashSet<T>,
writes: HashSet<T>,
}

impl<T: Hash + Eq + PartialEq> Default for TypeAccess<T> {
fn default() -> Self {
Self {
reads_all: false,
writes_all: false,
reads_and_writes: Default::default(),
writes: Default::default(),
reads: Default::default(),
}
}
}
Expand All @@ -307,36 +228,72 @@ impl<T: Hash + Eq + PartialEq + Copy> TypeAccess<T> {
for write in writes {
type_access.add_write(write);
}

for read in reads {
type_access.add_read(read);
}

type_access
}

pub fn is_compatible(&self, other: &TypeAccess<T>) -> bool {
self.writes.is_disjoint(&other.reads_and_writes)
&& self.reads_and_writes.is_disjoint(&other.writes)
if self.writes_all() {
!other.writes_all && !other.reads_all && other.reads_and_writes.is_empty()
} else if self.reads_all {
!other.writes_all && other.writes.is_empty()
} else {
self.writes.is_disjoint(&other.reads_and_writes)
&& self.reads_and_writes.is_disjoint(&other.writes)
}
}

pub fn get_conflict<'a>(&'a self, other: &'a TypeAccess<T>) -> AccessConflict<'a, T> {
let conflict = self.writes.find_conflict(&other.reads_and_writes);
if let AccessConflict::None = conflict {
return self.reads_and_writes.find_conflict(&other.writes);
if self.writes_all {
if other.writes_all || other.reads_all {
AccessConflict::All
} else {
match other.reads_and_writes.iter().next() {
Some(element) => AccessConflict::Element(element),
None => AccessConflict::None,
}
}
} else if self.reads_all {
if other.writes_all {
AccessConflict::All
} else {
match other.writes.iter().next() {
Some(element) => AccessConflict::Element(element),
None => AccessConflict::None,
}
}
} else if other.writes_all {
match self.reads_and_writes.iter().next() {
Some(element) => AccessConflict::Element(element),
None => AccessConflict::None,
}
} else if other.reads_all {
match self.writes.iter().next() {
Some(element) => AccessConflict::Element(element),
None => AccessConflict::None,
}
} else {
match self.writes.intersection(&other.reads_and_writes).next() {
Some(element) => AccessConflict::Element(element),
None => match other.writes.intersection(&self.reads_and_writes).next() {
Some(element) => AccessConflict::Element(element),
None => AccessConflict::None,
},
}
}
conflict
}

pub fn extend(&mut self, other: &TypeAccess<T>) {
self.reads_all = self.reads_all || other.reads_all;
self.writes_all = self.writes_all || other.writes_all;
self.writes.extend(&other.writes);
self.reads.extend(&other.reads);
self.reads_and_writes.extend(&other.reads_and_writes);
}

pub fn add_read(&mut self, ty: T) {
self.reads_and_writes.insert(ty);
self.reads.insert(ty);
}

pub fn add_write(&mut self, ty: T) {
Expand All @@ -345,51 +302,53 @@ impl<T: Hash + Eq + PartialEq + Copy> TypeAccess<T> {
}

pub fn read_all(&mut self) {
self.reads_and_writes = AccessSet::All;
self.reads = AccessSet::All;
self.reads_all = true;
}

pub fn write_all(&mut self) {
self.reads_and_writes = AccessSet::All;
self.writes = AccessSet::All;
self.reads_all = true;
self.writes_all = true;
}

/// NB: does not reset access sets that have been set to `All`.
pub fn clear(&mut self) {
self.reads_all = false;
self.writes_all = false;
self.reads_and_writes.clear();
self.reads.clear();
self.writes.clear();
}

pub fn is_read_or_write(&self, ty: &T) -> bool {
self.reads_and_writes.contains(ty)
self.reads_all || self.writes_all || self.reads_and_writes.contains(ty)
}

pub fn is_write(&self, ty: &T) -> bool {
self.writes.contains(ty)
self.writes_all || self.writes.contains(ty)
}

pub fn reads_all(&self) -> bool {
self.reads == AccessSet::All
self.reads_all
}

pub fn writes_all(&self) -> bool {
self.writes == AccessSet::All
self.writes_all
}

/// Returns an iterator of distinct accessed types if neither write nor read access is `All`.
/// Returns an iterator of distinct accessed types if only some types are accessed.
pub fn all_distinct_types(&self) -> Option<impl Iterator<Item = &T>> {
self.reads_and_writes.distinct_iterator()
if !(self.reads_all || self.writes_all) {
return Some(self.reads_and_writes.iter());
}
None
}

pub fn condense(&self, all_types: &[T]) -> CondensedTypeAccess {
if self.writes_all() {
if self.writes_all {
unreachable!(
"Access for systems that exclusively access all of `World`\
or `Resources` should never be condensed."
)
}
if self.reads_all() {
if self.reads_all {
let mut writes = FixedBitSet::with_capacity(all_types.len());
for (index, access_type) in all_types.iter().enumerate() {
if self.writes.contains(access_type) {
Expand Down

0 comments on commit c4e8261

Please sign in to comment.