Abandoned atoms work: hardly any performance benefit.
[sod] / lib / keyword.h
index 783f0b7..58dd29c 100644 (file)
@@ -113,6 +113,44 @@ typedef void kw_unkhookfn(const char */*set*/, const char */*kw*/);
  */
 extern kw_unkhookfn *kw_unkhook;
 
+/*----- Atoms -------------------------------------------------------------*/
+
+#ifdef __arm__
+#  define KW__SECTTY "%"
+#else
+#  define KW__SECTTY "@"
+#endif
+
+#if defined(__GNUC__) && defined(__ELF__) && 0
+#  define KWATOM_DECL(id, name)                                                \
+       __asm__(        ".ifndef " #id "\n"                             \
+                       ".pushsection .rodata." #id ", "                \
+                               "\"aGS\", " KW__SECTTY "progbits, "     \
+                               ".rodata." #id ", comdat\n"             \
+                       ".globl " #id "\n"                              \
+               #id ": .asciz " #name "\n"                              \
+                       ".popsection\n"                                 \
+                       ".endif");                                      \
+       extern const char id[]
+#endif
+
+#ifdef KWATOM_DECL
+#  define KW_ATOM(id, name) id
+#else
+#  define KWATOM_DECL(id, name) extern int kw__fake_##id
+#  define KW_ATOM(id, name) (name + 0*sizeof(kw__fake_##id))
+#endif
+
+#define KADECL(atom) KWATOM_DECL(kw__atom__##atom, #atom)
+#define KA(atom) KW_ATOM(kw__atom__##atom, #atom)
+#define KA_TAB KW_ATOM(kw__atom_kw_tab, "kw.tab")
+#define KA_UNKNOWN KW_ATOM(kw__atom_kw_unknown, "kw.unknown")
+#define KA_VALIST KW_ATOM(kw__atom_kw_valist, "kw.valist")
+
+KWATOM_DECL(kw__atom_kw_tab, "kw.tab");
+KWATOM_DECL(kw__atom_kw_unknown, "kw.unknown");
+KWATOM_DECL(kw__atom_kw_valist, "kw.valist");
+
 /*----- Argument list macros ----------------------------------------------*/
 
 /* These macros are intended to be conveniences rather than a proper
@@ -158,7 +196,7 @@ extern kw_unkhookfn *kw_unkhook;
   /* Slight hack.  The @KWCALL@ macro sets GCC and similar compilers up to
    * check for a sentinal null pointer at the end of the variable-length
    * argument tail.  Alas, if there are no keywords at all, then the null
-   * terminator ends up in the @kwfirst_@ argument, and the tail is propetly
+   * terminator ends up in the @kwfirst_@ argument, and the tail is properly
    * empty, with the result that the compiler gives an annoying warning.
    * Supplying an extra argument here is obviously harmless, and makes the
    * otherwise useful warning go away in this case where it's not wanted.
@@ -172,9 +210,9 @@ extern kw_unkhookfn *kw_unkhook;
  * Use:                Bundles a keyword @kw@ and value @val@ together.
  */
 
-#define K(kw, val) #kw, (val),
+#define K(kw, val) KA(kw), (val),
 
-/* --- @KW_VALIST@ --- *
+/* --- @K_VALIST@ --- *
  *
  * Arguments:  @va_list ap@ = argument-list extraction state
  *
@@ -182,9 +220,9 @@ extern kw_unkhookfn *kw_unkhook;
  *             function.
  */
 
-#define K_VALIST(ap) "kw.valist", &(ap),
+#define K_VALIST(ap) KA_VALIST, &(ap),
 
-/* --- @KW_TAB@ --- *
+/* --- @K_TAB@ --- *
  *
  * Arguments:  @const struct kwval *v@ = base address of argument vector
  *             @size_t n@ = length of argument vector
@@ -193,7 +231,7 @@ extern kw_unkhookfn *kw_unkhook;
  *             function.
  */
 
-#define K_TAB(v, n) "kw.tab", (v), (size_t)(n),
+#define K_TAB(v, n) KA_TAB, (v), (size_t)(n),
 
 /*----- Keyword set definitions -------------------------------------------*
  *
@@ -235,7 +273,7 @@ extern kw_unkhookfn *kw_unkhook;
     set##_KWSET(KWSET__SUPPLIEDP)                                      \
     set##_KWSET(KWSET__STRUCTMEM)                                      \
   }
-#define KWSET__SUPPLIEDP(type, name, dflt) unsigned name##_suppliedp : 1;
+#define KWSET__SUPPLIEDP(type, name, dflt) unsigned name##_suppliedp: 1;
 #define KWSET__STRUCTMEM(type, name, dflt) type name;
 
 /* --- @KWSET_PARSEFN@ --- *
@@ -322,7 +360,8 @@ extern kw_unkhookfn *kw_unkhook;
     size_t nn;                                                         \
                                                                        \
     for (k = kwfirst; k; k = va_arg(*ap, const char *)) {              \
-      if (!strcmp(k, "kw.valist")) {                                   \
+      set##_KWSET(KWSET__ARGVA)                                                \
+      /*else*/ if (!strcmp(k, "kw.valist")) {                          \
        aap = va_arg(*ap, va_list *);                                   \
        kk = va_arg(*aap, const char *);                                \
        set##_kwparse(kw, kk, aap, 0, 0);                               \
@@ -330,36 +369,103 @@ extern kw_unkhookfn *kw_unkhook;
        vv = va_arg(*ap, const struct kwval *);                         \
        nn = va_arg(*ap, size_t);                                       \
        set##_kwparse(kw, 0, 0, vv, nn);                                \
-      }                                                                        \
-      set##_KWSET(KWSET__ARGVA)                                                \
-      else kw_unknown(#set, k);                                                \
+      } else kw_unknown(#set, k);                                      \
     }                                                                  \
                                                                        \
     while (n) {                                                                \
-      if (!strcmp(v->kw, "kw.valist")) {                               \
+      set##_KWSET(KWSET__ARGTAB)                                       \
+      /*else*/ if (!strcmp(v->kw, "kw.valist")) {                      \
        aap = *(va_list *const *)v->val;                                \
        kk = va_arg(*aap, const char *);                                \
        set##_kwparse(kw, kk, aap, 0, 0);                               \
       } else if (!strcmp(v->kw, "kw.tab")) {                           \
        t = (const struct kwtab *)v->val;                               \
        set##_kwparse(kw, 0, 0, t->v, t->n);                            \
-      }                                                                        \
-      set##_KWSET(KWSET__ARGTAB)                                       \
-      else kw_unknown(#set, v->kw);                                    \
+      } else kw_unknown(#set, v->kw);                                  \
       v++; n--;                                                                \
     }                                                                  \
   }
+
 #define KWSET__ARGVA(type, name, dflt)                                 \
-  else if (!strcmp(k, #name)) {                                                \
+  if (!strcmp(k, #name)) {                                             \
     kw->name##_suppliedp = 1;                                          \
     kw->name = va_arg(*ap, type);                                      \
-  }
+  } else
 #define KWSET__ARGTAB(type, name, dflt)                                        \
-  else if (!strcmp(v->kw, #name)) {                                    \
+  if (!strcmp(v->kw, #name)) {                                         \
     kw->name##_suppliedp = 1;                                          \
     kw->name = *(type const *)v->val;                                  \
+  } else
+
+#define KWSET_PARSEFN_ATOMS(set)                                       \
+  void set##_kwparse(struct set##_kwargs *kw,                          \
+                    const char *kwfirst, va_list *ap,                  \
+                    const struct kwval *v, size_t n)                   \
+  {                                                                    \
+    const char *k, *kk;                                                        \
+    va_list *aap;                                                      \
+    const struct kwtab *t;                                             \
+    const struct kwval *vv;                                            \
+    size_t nn;                                                         \
+                                                                       \
+    for (k = kwfirst; k; k = va_arg(*ap, const char *)) {              \
+      set##_KWSET(KWSET__ARGVA_ATOM)                                   \
+      /*else*/ if (k == KA_VALIST) {                                   \
+       aap = va_arg(*ap, va_list *);                                   \
+       kk = va_arg(*aap, const char *);                                \
+       set##_kwparse(kw, kk, aap, 0, 0);                               \
+      } else if (k == KA_TAB) {                                                \
+       vv = va_arg(*ap, const struct kwval *);                         \
+       nn = va_arg(*ap, size_t);                                       \
+       set##_kwparse(kw, 0, 0, vv, nn);                                \
+      } else set##_KWSET(KWSET__ARGVA)                                 \
+      /*else*/ if (!strcmp(k, KA_VALIST)) {                            \
+       aap = va_arg(*ap, va_list *);                                   \
+       kk = va_arg(*aap, const char *);                                \
+       set##_kwparse(kw, kk, aap, 0, 0);                               \
+      } else if (!strcmp(k, KA_TAB)) {                                 \
+       vv = va_arg(*ap, const struct kwval *);                         \
+       nn = va_arg(*ap, size_t);                                       \
+       set##_kwparse(kw, 0, 0, vv, nn);                                \
+      } else kw_unknown(#set, k);                                      \
+    }                                                                  \
+                                                                       \
+    while (n) {                                                                \
+      set##_KWSET(KWSET__ARGTAB)                                       \
+      /*else*/ if (!strcmp(v->kw, KA_VALIST)) {                                \
+       aap = *(va_list *const *)v->val;                                \
+       kk = va_arg(*aap, const char *);                                \
+       set##_kwparse(kw, kk, aap, 0, 0);                               \
+      } else if (!strcmp(v->kw, KA_TAB)) {                             \
+       t = (const struct kwtab *)v->val;                               \
+       set##_kwparse(kw, 0, 0, t->v, t->n);                            \
+      } else kw_unknown(#set, v->kw);                                  \
+      v++; n--;                                                                \
+    }                                                                  \
   }
 
+#define KWSET__ARGVA_ATOM(type, name, dflt)                            \
+  if (k == KA(name)) {                                                 \
+    kw->name##_suppliedp = 1;                                          \
+    kw->name = va_arg(*ap, type);                                      \
+  } else
+#define KWSET__ARGTAB_ATOM(type, name, dflt)                           \
+  if (v->kw == KA(name)) {                                             \
+    kw->name##_suppliedp = 1;                                          \
+    kw->name = *(type const *)v->val;                                  \
+  } else
+
+#define KWSET__ARGVA(type, name, dflt)                                 \
+  if (!strcmp(k, #name)) {                                             \
+    kw->name##_suppliedp = 1;                                          \
+    kw->name = va_arg(*ap, type);                                      \
+  } else
+#define KWSET__ARGTAB(type, name, dflt)                                        \
+  if (!strcmp(v->kw, #name)) {                                         \
+    kw->name##_suppliedp = 1;                                          \
+    kw->name = *(type const *)v->val;                                  \
+  } else
+
 /*----- Defining keyword-accepting functions ------------------------------*/
 
 /* --- @KWDECL@ --- *
@@ -471,8 +577,8 @@ extern kw_unkhookfn *kw_unkhook;
  * Use:                Copies arguments from the source structure @kw@ into the
  *             vector @v@.  The structure @kw@ must have type @struct
  *             fromset_kwargs *@.  The argument @v@ must have type @struct
- *             kwval *@ (after array-to- pointer decay), and there must be a
- *             variable @v_n@ of sufficiently large integral type suitably
+ *             kwval *@ (after array-to-pointer decay), and there must be a
+ *             variable @n@ of sufficiently large integral type suitably
  *             initialized.  Elements of the vector, starting with element
  *             @n@, will be filled in with those keyword arguments defined
  *             in @toset@ -- which must be a subset of @srcsrc@ from @kw@