PERF: Index._shallow_copy shares _cache with copies of self
#32640 copied the cache when copying indexes. Indexes are immutable, so some refactoring allows us to __share__ the cache instead. This means potentially fewer expensive index ops.

```python
>>> idx = pd.CategoricalIndex(np.arange(100_000))
>>> copied = idx.copy()
>>> copied._cache
{}
>>> idx.get_loc(99_999)
>>> copied._cache
{'_engine': <pandas._libs.index.Int32Engine at 0x1fd3a6934c8>}  # don't need to recreate _engine on copied
```

Performance example:
```python
>>> idx = pd.CategoricalIndex(np.arange(100_000))
>>> %timeit idx._shallow_copy().get_loc(99_999)
4.09 ms ± 65 µs per loop  # master
7.71 µs ± 355 ns per loop  # this PR
```
