From 486f576c835d4a8e1806f88cd2a6ee884b6a97ca Mon Sep 17 00:00:00 2001
From: gokl <gokl@gokl.goklfake>
Date: Thu, 24 Oct 2013 16:29:57 +0200
Subject: [PATCH] * do red-black tree search for language code lookups

---
 src/lang_codes.c | 65 ++++++++++++++++++++++++++++++++++++++++++------
 src/lang_codes.h | 10 ++++++++
 2 files changed, 68 insertions(+), 7 deletions(-)

diff --git a/src/lang_codes.c b/src/lang_codes.c
index 0e92599b..a6e9b730 100644
--- a/src/lang_codes.c
+++ b/src/lang_codes.c
@@ -495,14 +495,60 @@ const lang_code_t lang_codes[] = {
   { NULL, NULL, NULL, NULL }
 };
 
+lang_code_lookup_t* lang_codes_code2b = NULL;
+lang_code_lookup_t* lang_codes_code1 = NULL;
+lang_code_lookup_t* lang_codes_code2t = NULL;
+
 /* **************************************************************************
  * Functions
  * *************************************************************************/
 
+/* Compare language codes */
+static int _lang_code2b_cmp ( void *a, void *b )
+{
+  return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code2b,
+      ((lang_code_lookup_element_t*)b)->lang_code->code2b);
+}
+
+static int _lang_code1_cmp ( void *a, void *b )
+{
+  return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code1,
+      ((lang_code_lookup_element_t*)b)->lang_code->code1);
+}
+
+static int _lang_code2t_cmp ( void *a, void *b )
+{
+  return strcmp(((lang_code_lookup_element_t*)a)->lang_code->code2t,
+      ((lang_code_lookup_element_t*)b)->lang_code->code2t);
+}
+
+static int _lang_code_lookup_add( lang_code_lookup_t* lookup_table, const lang_code_t *code, int (*func)(void*, void*) ) {
+  lang_code_lookup_element_t *element;
+  element = (lang_code_lookup_element_t *)calloc(1, sizeof(lang_code_lookup_element_t));
+  element->lang_code = code;
+  RB_INSERT_SORTED(lookup_table, element, link, func);
+  return 0;
+}
+
 static const lang_code_t *_lang_code_get ( const char *code, size_t len )
 {
   int i;
   char tmp[4];
+  
+  if (lang_codes_code2b == NULL) {
+    const lang_code_t *c = lang_codes;
+
+    lang_codes_code2b = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
+    lang_codes_code1 = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
+    lang_codes_code2t = (lang_code_lookup_t *)calloc(1, sizeof(lang_code_lookup_t));
+
+    while (c->code2b) {
+      _lang_code_lookup_add(lang_codes_code2b, c, _lang_code2b_cmp);
+      if (c->code1) _lang_code_lookup_add(lang_codes_code1, c, _lang_code1_cmp);
+      if (c->code2t) _lang_code_lookup_add(lang_codes_code2t, c, _lang_code2t_cmp);
+      c++;
+    }
+  }
 
   if (code && *code && len) {
 
@@ -527,13 +573,18 @@ static const lang_code_t *_lang_code_get ( const char *code, size_t len )
 
     /* Search */
     if (i) {
-      const lang_code_t *c = lang_codes;
-      while (c->code2b) {
-        if ( !strcmp(tmp, c->code2b) )              return c;
-        if ( c->code1  && !strcmp(tmp, c->code1) )  return c;
-        if ( c->code2t && !strcmp(tmp, c->code2t) ) return c;
-        c++;
-      }
+      lang_code_lookup_element_t sample, *element;
+      lang_code_t lang_code;
+      lang_code.code1 = tmp;
+      lang_code.code2b = tmp;
+      lang_code.code2t = tmp;
+      sample.lang_code = &lang_code;
+      element = RB_FIND(lang_codes_code2b, &sample, link, _lang_code2b_cmp);
+      if (element != NULL) return element->lang_code;
+      element = RB_FIND(lang_codes_code1, &sample, link, _lang_code1_cmp);
+      if (element != NULL) return element->lang_code;
+      element = RB_FIND(lang_codes_code2t, &sample, link, _lang_code2t_cmp);
+      if (element != NULL) return element->lang_code;
     }
   }
   return &lang_codes[0];
diff --git a/src/lang_codes.h b/src/lang_codes.h
index 0a79fc19..9be6d174 100644
--- a/src/lang_codes.h
+++ b/src/lang_codes.h
@@ -19,6 +19,8 @@
 #ifndef __TVH_LANG_CODES_H__
 #define __TVH_LANG_CODES_H__
 
+#include "redblack.h"
+
 typedef struct lang_code
 {
   const char *code2b; ///< ISO 639-2 B
@@ -38,4 +40,12 @@ const lang_code_t *lang_code_get3 ( const char *code );
 const char **lang_code_split ( const char *codes );
 const lang_code_t **lang_code_split2 ( const char *codes );
 
+/* Efficient code lookup */
+typedef struct lang_code_lookup_element {
+  RB_ENTRY(lang_code_lookup_element) link;
+  const lang_code_t *lang_code;
+} lang_code_lookup_element_t;
+
+typedef RB_HEAD(lang_code_lookup, lang_code_lookup_element) lang_code_lookup_t;
+
 #endif /* __TVH_LANG_CODES_H__ */