Remove use of numpy structured arrays in table operations

PR #2790 did not address the high-level table operations `hstack`, `vstack`, and `join`.  These are implemented in two-tiered approach: the low-level tier in `np_utils.py` used pure numpy structured arrays to do the heavy lifting while the high-level `operations.py` provided the Table interface.  The problem after #2790 is that these operations required creating temporary numpy structured arrays to represent the tables.

This PR updates the low-level code to do the operations directly with Table objects and largely eliminates use of numpy structured arrays.

In the current version of the PR, the module `np_utils.py` is basically orphaned, at least from the Table perspective.  The functions there were nominally public so we need to decide whether to deprecate them or just leave as a useful utility.