Subject: bug#30458: 26.0; `ucs-names': No reverse lookup function now

From: Drew Adams <[email-masked]>
Date: Wed, 14 Feb 2018 09:41:10 -0800 (PST)

Before Emacs 26, `ucs-names' was an alist.  That meant that you could
not only look up a character, given its name or code, but you could also
easily look up a character name, given the character:

(car (rassq CHARACTER (ucs-names)))

How is this done now, with (ucs-names) returning a hash table?

There is now a function `char-from-name', to replace the former forward
alist lookup (car (assoc CHAR-NAME (ucs-names))).  But there doesn't
seem to be any reverse lookup now for `ucs-names' (e.g. `char-name' or
`char-name-from-char').

Seems like it should be possible to have such a reverse-lookup function
for any hash table (perhaps coded in C).

Sure, just like an alist, a hash table can have multiple keys that have
the same value.  And the order in a hash table is undefined, so when
there are multiple keys for the same value, a function that gives you
the key when you pass it the value can only give you one of those keys.
But that might be better than nothing.

Another possibility would be to have a function that returns all keys
that have the same value.

For example, naively (with lexical-binding):

(defun get-hash-keys (value hash-table &optional value-test-function)
  "Return a list of keys associated with VALUE in HASH-TABLE.
Optional arg VALUE-TEST-FUNCTION (default `equal') is the equality
predicate used to compare values."
  (setq value-test-function  (or value-test-function  #'equal))
  (let ((keys  ()))
    (maphash (lambda (key val)
               (when (funcall value-test-function val value)
                 (push key keys)))
             hash-table)
    keys))

Then:

(get-hash-keys (char-from-name "GREEK SMALL LETTER LAMBDA")
               (ucs-names))

returns ("GREEK SMALL LETTER LAMBDA" "GREEK SMALL LETTER LAMDA").

And for example:

(defun get-a-hash-key (value hash-table &optional value-test-function)
  "Return a hash key associated with VALUE in HASH-TABLE.
If there is more than one such key then it is undefined which is
returned.
Optional arg VALUE-TEST-FUNCTION (default `equal') is the equality
predicate used to compare values."
  (setq value-test-function  (or value-test-function  #'equal))
  (catch 'get-a-hash-key
    (maphash (lambda (key val)
               (when (funcall value-test-function val value)
                 (throw 'get-a-hash-key key)))
             hash-table)
    nil))

Then:

(get-a-hash-key (char-from-name "GREEK SMALL LETTER LAMBDA")
                (ucs-names))

returns "GREEK SMALL LETTER LAMDA" (though one would probably prefer
"GREEK SMALL LETTER LAMBDA").

For the reverse-lookup functions (reverse of `char-from-name') for
a character we would have:

(defun char-names (character)
  "Return a list of the names for CHARACTER."
  (get-hash-keys character (ucs-names)))

(defun char-name (character)
  "Return a name for CHARACTER, from `ucs-names'."
  (get-a-hash-key character (ucs-names)))

Please consider adding such reverse-lookup functions for hash
tables (whether using such an implementation or something else),
and adding specific such functions for `ucs-names', to accompany
the forward-lookup function `char-from-name'.

In GNU Emacs 26.0.91 (build 1, x86_64-w64-mingw32)
 of 2018-01-22
Repository revision: 752fba992b793a74d202c9cfc3e1a92fd458e748
Windowing system distributor `Microsoft Corp.', version 6.1.7601
Configured using:
 `configure --without-dbus --host=x86_64-w64-mingw32
 --without-compress-install 'CFLAGS=-O2 -static -g3''