ENH: Add return_inverse to cython-unique; unify unique/factorize-code
This is a continuation/split-off from #22986, where I tried to deduplicate the cython code for `unique`/`factorize`, and add a `return_inverse` kwarg to `unique` at the same time. This didn't fully work because there was a performance impact that was deemed unacceptable. I've opened cython/cython#2660 to figure out why (resp. have a directive to allow force-compilation of different parameter values, which would solve this more elegantly), and @robertwb told me that it's likely the use of kwargs, but also suggested the possibility to use explicit templating on `return_inverse`.

First I tried unification without any kwargs in https://github.com/pandas-dev/pandas/pull/23400/commits/858f54e5e4d5e84f2a45f7c5954cbde9fb6d9438 - this still had the same perf impact as in #22986.
Then I added the explict templating in https://github.com/pandas-dev/pandas/pull/23400/commits/4ed354a9544d0576aa1b98ffd26d3667677ed6ea, which successfully avoids the perf impact, but is a bit uglier in the `pxi.in`. Finally, I've readded the kwargs in https://github.com/pandas-dev/pandas/pull/23400/commits/906cd50e8391148a19fb93487b7fedb25ab9e767 to keep the diff here smaller, and this doesn't have an impact.

I've had many unsuccessful tries to run the ASVs for all those combinations over the weekend, so I'm going back to explicitly testing the unique-code here (code at the end). The overview is as follows (for completeness I've added the #22986 and the commit immediately prior on master; all results in milliseconds):
```
>>> df
                  e5196aaac6 99e640186e caea25a8b9 858f54e5e4 4ed354a954  906cd50e83 0d6dad0ca1
                    #22986~1     #22986     master  no kwargs  templated tmpl+kwargs  PR+master
StringIndex        16.220276  16.023982  15.967190  15.706223  15.624902   14.952832  15.480224
CategoricalIndex    1.274368   1.289882   1.231592   1.400420   1.247882    1.250814   1.327520
IntIndex            2.743178   2.778960   2.722282   3.115781   2.818848    2.802402   2.877664
UIntIndex           2.760333   2.773203   2.714546   3.037279   2.786909    2.800675   2.914427
RangeIndex          2.765113   2.773916   2.804379   3.071501   2.801661    2.803809   2.816012
FloatIndex          4.734558   4.576122   4.575152   5.043915   4.518481    4.548134   4.732967
TimedeltaIndex      4.361350   4.238442   4.187650   4.601932   4.369402    4.409724   4.422439
StringSeries       59.779114  58.508761  57.742805  58.343838  58.266719   57.043169  58.619018
CategoricalSeries   2.708816   2.666240   2.627852   2.895955   2.664937    2.658149   2.715396
IntSeries           5.078922   4.991856   4.928836   5.480455   5.108894    5.096692   5.434841
UIntSeries          5.127376   4.984227   5.027707   5.445736   5.155703    5.080125   5.211029
RangeSeries         5.218271   5.013379   4.973759   5.531086   5.193241    5.091924   5.197651
FloatSeries         7.126269   6.959626   6.988052   7.738704   6.977395    6.978753   7.215513
TimedeltaSeries     5.146969   4.985955   5.024334   5.551364   5.153091    5.108740   5.158593
```
or, relatively to the commit on master I was basing myself on:
```
>>> df.divide(df.iloc[:, 2], axis=0)
                  e5196aaac6 99e640186e caea25a8b9 858f54e5e4 4ed354a954  906cd50e83 0d6dad0ca1
                    #22986~1     #22986     master  no kwargs  templated tmpl+kwargs  PR+master
StringIndex         1.015850   1.003557        1.0   0.983656   0.978563    0.936472   0.969502
CategoricalIndex    1.034733   1.047329        1.0   1.137081   1.013227    1.015607   1.077889
IntIndex            1.007676   1.020820        1.0   1.144547   1.035472    1.029431   1.057078
UIntIndex           1.016868   1.021608        1.0   1.118890   1.026658    1.031729   1.073633
RangeIndex          0.985999   0.989138        1.0   1.095252   0.999031    0.999797   1.004148
FloatIndex          1.034842   1.000212        1.0   1.102458   0.987613    0.994095   1.034494
TimedeltaIndex      1.041479   1.012129        1.0   1.098930   1.043402    1.053031   1.056067
StringSeries        1.035265   1.013265        1.0   1.010409   1.009073    0.987884   1.015174
CategoricalSeries   1.030810   1.014608        1.0   1.102024   1.014112    1.011529   1.033314
IntSeries           1.030450   1.012786        1.0   1.111917   1.036531    1.034056   1.102662
UIntSeries          1.019824   0.991352        1.0   1.083145   1.025458    1.010426   1.036462
RangeSeries         1.049160   1.007966        1.0   1.112053   1.044128    1.023758   1.045015
FloatSeries         1.019779   0.995932        1.0   1.107419   0.998475    0.998669   1.032550
TimedeltaSeries     1.024408   0.992361        1.0   1.104895   1.025627    1.016799   1.026722
```

So long story short, this PR prepares the hashtable-backend to support `return_inverse=True`, which plays into #21357 #21645 #22824, and will also allow to easily solve #21720.

Code for the above timings:
```
import pandas as pd
import numpy as np
import pandas.util.testing as tm
import timeit
hash = pd.__git_version__[:10]

k = 10 ** 5
rep = 10
number = 100
tic = timeit.default_timer()
tags = ['String', 'Categorical', 'Int', 'UInt',
         'Range', 'Float', 'Timedelta']
df = pd.DataFrame(index = [x+'Index' for x in tags], columns = ['mean', 'std'])
np.random.seed(55555)
with tm.RNGContext(55555):
    for tag in tags:
        idx = getattr(tm, f'make{tag}Index')(k=k)
        t = timeit.repeat('idx.unique()', setup='from __main__ import idx', repeat = rep+1, number = number)[1:]
        df.loc[tag+'Index', 'mean'] = pd.Series(t).mean() / number
        df.loc[tag+'Index', 'std'] = pd.Series(t).std() / number
        
        s = pd.Series(idx).sample(frac=2, replace=True)
        t = timeit.repeat('s.unique()', setup='from __main__ import s', repeat = rep+1, number = number)[1:]
        df.loc[tag+'Series', 'mean'] = pd.Series(t).mean() / number
        df.loc[tag+'Series', 'std'] = pd.Series(t).std() / number
df.to_csv(f'test_{hash}.csv')
```