API: Make Categorical.searchsorted returns a scalar when supplied a scalar
- [x] closes #21019
- [x] tests added / passed
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

``Categorical.searchsorted`` returns the wrong shape for scalar input. Numpy arrays and all other array types return a scalar if the input is a scalar, but ``Categorical`` does not.

For example:

```python
>>> import numpy as np
>>> np.array([1, 2, 3]).searchsorted(1)
0
>>> np.array([1, 2, 3]).searchsorted([1])
array([0])
>>> import pandas as pd
>>> d = pd.date_range('2018', periods=4)
>>> d.searchsorted(d[0])
0
>>> d.searchsorted(d[:1])
array([0])

>>> n = 100_000
>>> c = pd.Categorical(list('a' * n + 'b' * n + 'c' * n), ordered=True)
>>> c.searchsorted('b')
array([100000], dtype=int32)  # master
100000  # this PR. Scalar input should lead to scalar output
>>> c.searchsorted(['b'])
array([100000], dtype=int32)  # master and this PR
```

This new implementation is BTW quite a bit faster than the old implementation, because we avoid recoding the codes when doing the ``self.codes.searchsorted(code, ...)`` bit:

```python
>>> %timeit c.searchsorted('b')
237 µs  # master
6.12 µs  # this PR
```

A concequence of the new implementation is that KeyError is now raised when a key isn't found. Previously a ValueError was raised.
