Thanks for the very quick review!
Schema.find: I'm unhappy that you have changed it to mutate the name...
Actually, I haven't: because I'm passing the string by value, not by reference, I'm actually modifying a temporary. Doing it this way instead of passing by const reference and creating an explicit temporary just gives the compiler more options how how to optimize the function. It's a fine line between premature optimization and good (but perhaps confusingly advanced) C++ practice, so if you'd prefer I use const reference and an explicit temporary I'd be happy to make the switch. This goes for AliasMap::apply() as well.
Schema.getAliasMap returns a map that that is a shared pointer to the version inside Schema; modifying the returned value modifies the one inside the Schema. Exposing internals like that worries me, but I'm betting you had good reason to do it this way, such as sharing alias maps between schemas? (I admit I'm not sure why that's useful, though it sounds interesting). But just in case it is practical, I'll mention an obvious safer-but-clumsier alternative: return a copy, which the user can modify as they like and then call Schema.setAliasMap to make changes.
This is the ugliness I settled on after our conversation yesterday; I think it was either this, something uglier, or a major refactor. While the the fact that Schemas share aliases may be confusing in some (hopefully rare) cases, it's what we want 99% of the time, because copying two Schemas usually just happens because you've called e.g. catalog.getSchema(), and that returns a copy. So this lets us modify the AliasMap through that copy, which is what we want.
What does AliasMap.apply do? I found the description too vague. My guess is that it's like AliasMap.get but expands abbreviations. However, it also apparently modifies the input argument; if so, this seems a misfeature, especially since it returns the result. Please document what happens if there is no match.
You guessed right about what it does, and I'll try to improve the docs to make that more obvious (now that I think about it, it really needs an example). As with Schema::find, as discussed above, it doesn't actually modify the input argument (well, the private _apply() implementation does, but the public one does not).
What does AliasMap.get do if there is no match?
Throws NotFoundError. Will document.
What does AliasMap.remove do if there is no match?
Hmm; I think it does nothing. I'll check that, and make sure the C++ version is consistent with STL semantics and the Python "del" overload is consistent with what's expected there (an exception, I think). And I'll document it.
AliasMap.cc defines anonymous function startsWith but does not use it. Also, why define a new one instead of using boost::string::starts_with instead?
Oops, that's a relic that should be deleted. I didn't know about boost::string::starts_with (thanks!) when I added it, but then it turned out that the logic there was too intertwined with the search algorithm to separate.
testTableAliases.py: nit-pick: sys, os and numpy are imported but not used (let's hear it for pyflakes).
I'll remove them.
Because no good deed ever goes unpunished, and Russell already discussed this some with me, I'm asking him to review it.
This adds a new class, AliasMap, to afw::table. An AliasMap is held by a Schema, where it's used when field names are looked up. Aliases are simple string-to-string mappings that are also searched when a field is searched for, and can match not just the full field name but an incomplete prefix as well. There's also code here to notify owning Tables when an alias changes (this is in anticipation of
DM-419, in which we'll use these aliases to define slots), and to persist the aliases with the Schema.Changes are all in afw u/jbosch/
DM-417:afw:u/jbosch/DM-417 % git diff --stat master...u/jbosch/DM-417
.gitignore | 1 +
include/lsst/afw/fits.h | 4 +-
include/lsst/afw/table/AliasMap.h | 98 +++++++++++++++++++
include/lsst/afw/table/BaseTable.h | 7 +-
include/lsst/afw/table/Schema.h | 48 ++++++++--
include/lsst/afw/table/detail/SchemaImpl.h | 4 +-
python/lsst/afw/table/Base.i | 40 ++++++++
src/table/AliasMap.cc | 86 +++++++++++++++++
src/table/BaseTable.cc | 6 ++
src/table/Schema.cc | 40 ++++++--
src/table/io/FitsReader.cc | 20 ++++
src/table/io/FitsWriter.cc | 7 ++
tests/testSimpleTable.py | 3 +-
tests/testTableAliases.cc | 86 +++++++++++++++++
tests/testTableAliases.py | 143 ++++++++++++++++++++++++++++
15 files changed, 570 insertions(+), 23 deletions(-)