Move Element.__*cached variable to Artifact class

I'd suggest adding a __cached variable to the Artifact class to replace the Element variables __weak_cached and __strong_cached (or __strict_cached after the rename suggested in !1323 (comment 166065971)). And then change Artifact.cached() to return __cached, actually querying the (filesystem) cache only on the first call.

I think this would make a couple areas slightly simpler:

  • In _update_state():
    • Drop __strong_cached = None and __weak_cached = None as they will be implicitly discarded by discarding the artifact objects.
    • Drop the first real __weak_cached assignment as the first call to self.__artifact.cached() will cover this.
    • Replace the following conditional assignments to __strong_cached and __weak_cached with unconditional calls to self.__strict_artifact.update_cached() and self.__artifact.update_cached(). Artifact.update_cached() should do nothing if __cached is already True and otherwise ensure that the the next call to Artifact.cached() queries the (filesystem) cache again.
  • Element._cached() could be changed to a simple return self.__artifact.cached() (an early return if self.__artifact is still None may be required, to be determined).

_pull_pending()'s use of self.__strong_cached should be replaced with self.__strict_artifact.cached().

In future _update_state() splitting work, the update_cached() calls could likely be moved to points where we know that we need to requery the (filesystem) cache (after pulling and after building) instead of doing it unconditionally in _update_state(). However, that can be done in a separate step as the changes above are not expected to cause a performance regression.