Added SearchUShort and SearchULong.



git-svn-id: http://sfntly.googlecode.com/svn/trunk/cpp/src@57 672e30a5-4c29-85ac-ac6d-611c735e0a51
diff --git a/sfntly/data/readable_font_data.cc b/sfntly/data/readable_font_data.cc
index 8f43575..6ceb38c 100644
--- a/sfntly/data/readable_font_data.cc
+++ b/sfntly/data/readable_font_data.cc
@@ -16,6 +16,9 @@
 
 #include "sfntly/data/memory_byte_array.h"
 #include "sfntly/data/readable_font_data.h"
+
+#include <stdio.h>
+
 #include "sfntly/data/writable_font_data.h"
 #include "sfntly/port/exception_type.h"
 
@@ -156,6 +159,71 @@
   return array_->CopyTo(ba, BoundOffset(0), Length());
 }
 
+int32_t ReadableFontData::SearchUShort(int32_t start_index,
+                                       int32_t start_offset,
+                                       int32_t end_index,
+                                       int32_t end_offset,
+                                       int32_t length,
+                                       int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadUShort(start_index + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadUShort(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
+int32_t ReadableFontData::SearchULong(int32_t start_index,
+                                      int32_t start_offset,
+                                      int32_t end_index,
+                                      int32_t end_offset,
+                                      int32_t length,
+                                      int32_t key) {
+  int32_t location = 0;
+  int32_t bottom = 0;
+  int32_t top = length;
+  while (top != bottom) {
+    location = (top + bottom) / 2;
+    int32_t location_start = ReadULongAsInt(start_index
+                                            + location * start_offset);
+    if (key < location_start) {
+      // location is below current location
+      top = location;
+    } else {
+      // is key below the upper bound?
+      int32_t location_end = ReadULongAsInt(end_index + location * end_offset);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "**start: %d; end: %d\n", location_start, location_end);
+#endif
+      if (key <= location_end) {
+        return location;
+      } else {
+        // location is above the current location
+        bottom = location + 1;
+      }
+    }
+  }
+  return -1;
+}
+
 CALLER_ATTACH FontData* ReadableFontData::Slice(int32_t offset,
                                                 int32_t length) {
   if (offset < 0 || offset + length > Size()) {
diff --git a/sfntly/data/readable_font_data.h b/sfntly/data/readable_font_data.h
index e7b3170..48b3e77 100644
--- a/sfntly/data/readable_font_data.h
+++ b/sfntly/data/readable_font_data.h
@@ -180,15 +180,55 @@
   // Make gcc -Woverloaded-virtual happy.
   virtual int32_t CopyTo(ByteArray* ba);
 
-  // TODO(dfilimon): Implementation of following in review, need to merge.
+  // Search for the key value in the range tables provided.
+  //
+  //  The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by UShort values,
+  // ranges do not overlap, and are monotonically increasing.
+  //
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchUShort(int32_t start_index,
+                       int32_t start_offset,
+                       int32_t end_index,
+                       int32_t end_offset,
+                       int32_t length,
+                       int32_t key);
+
+  // Search for the key value in the range tables provided.
+  //
+  // The search looks through the start-end pairs looking for the key value. It
+  // is assumed that the start-end pairs are both represented by ULong values
+  // that can be represented within 31 bits, ranges do not overlap, and are
+  // monotonically increasing.
+  //
+  // @param startIndex the position to read the first start value from
+  // @param startOffset the offset between subsequent start values
+  // @param endIndex the position to read the first end value from
+  // @param endOffset the offset between subsequent end values
+  // @param length the number of start-end pairs
+  // @param key the value to search for
+  // @return the index of the start-end pairs in which the key was found; -1
+  //         otherwise
+  int32_t SearchULong(int32_t start_index,
+                      int32_t start_offset,
+                      int32_t end_index,
+                      int32_t end_offset,
+                      int32_t length,
+                      int32_t key);
+
+
+  // TODO(arthurhsu): IMPLEMENT
   /*
-  virtual int32_t SearchUShort(int32_t start, int32_t length, int32_t key);
-  virtual int32_t SearchUShort(int32_t start_index, int32_t start_offset,
-                               int32_t count_index, int32_t count_offset,
-                               int32_t length, int32_t key);
-  virtual int32_t SearchULong(int32_t start_index, int32_t start_offset,
-                              int32_t end_index, int32_t end_offset,
-                              int32_t length, int32_t key);
+  virtual int32_t ReadFUnit(int32_t index);
+  virtual int64_t ReadF2Dot14(int32_t index);
+  virtual int64_t ReadLongDateTime(int32_t index);
   */
 
   // Makes a slice of this FontData. The returned slice will share the data with
diff --git a/test/font_data_test.cc b/test/font_data_test.cc
index 4de6fff..ecf9a62 100644
--- a/test/font_data_test.cc
+++ b/test/font_data_test.cc
@@ -25,7 +25,114 @@
 namespace sfntly {
 
 const int32_t BYTE_ARRAY_SIZES[] =
-    {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000};
+  {1, 7, 127, 128, 129, 255, 256, 257, 666, 1023, 0x10000};
+
+// array data for searching
+const int32_t LOWER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 4, 7, 13, 127};
+const int32_t UPPER_BYTE_ARRAY_FOR_SEARCHING[] = {2, 5, 12, 16, 256};
+const int32_t kLowerByteArrayForSearchingLength = 5;
+const int32_t kUpperByteArrayForSearchingLength = 5;
+
+// search test result pairs - number to search for; index found at
+const int32_t SEARCH_TEST_PAIRS[][2] = {
+  {0, -1}, {1, -1}, {2, 0}, {3, -1}, {4, 1}, {5, 1}, {6, -1}, {12, 2},
+  {13, 3}, {17, -1}, {126, -1}, {127, 4}, {256, 4}, {257, -1}, {0x1000, -1}
+};
+const int32_t kSearchTestPairsLength = 15;
+
+// offset and start index data for searching data
+// array data size, lower_start_index, lower_offset, upper_start_index,
+// upper_offset
+const int32_t SEARCH_TEST_OFFSETS[][5] = {
+  // lower[], upper[]
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * sizeof(ushort),
+    0,
+    sizeof(ushort),
+    kLowerByteArrayForSearchingLength * sizeof(ushort),
+    sizeof(ushort) },
+
+  // {lower, upper} []
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * sizeof(ushort),
+    0,
+    2 * sizeof(ushort),
+    sizeof(ushort),
+    2 * sizeof(ushort) },
+
+  // upper[], lower[]
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * sizeof(ushort),
+    kLowerByteArrayForSearchingLength * sizeof(ushort),
+    sizeof(ushort),
+    0,
+    sizeof(ushort) },
+
+  // {upper, lower} []
+  { (kLowerByteArrayForSearchingLength + kUpperByteArrayForSearchingLength)
+    * sizeof(ushort),
+    sizeof(ushort),
+    2 * sizeof(ushort),
+    0,
+    2 * sizeof(ushort) }
+};
+const int32_t kSearchTestOffsetLength = 4;
+
+ReadableFontData*
+FillTestFontDataWithShortsForSearching(WritableFontData* wfd,
+                                       const int32_t* lower_data,
+                                       int32_t lower_start_index,
+                                       int32_t lower_offset,
+                                       const int32_t* upper_data,
+                                       int32_t upper_start_index,
+                                       int32_t upper_offset) {
+  // lower data
+  int offset = lower_start_index;
+  for (int32_t i = 0; i < kLowerByteArrayForSearchingLength; ++i) {
+    wfd->WriteUShort(offset, lower_data[i]);
+    offset += lower_offset;
+  }
+
+  // upper data
+  offset = upper_start_index;
+  for (int32_t i = 0; i < kUpperByteArrayForSearchingLength; ++i) {
+    wfd->WriteUShort(offset, upper_data[i]);
+    offset += upper_offset;
+  }
+
+  return wfd;
+}
+
+bool TestReadableFontDataSearching() {
+  for (int32_t i = 0; i < kSearchTestOffsetLength; ++i) {
+    const int32_t* array_setup_offset = SEARCH_TEST_OFFSETS[i];
+    WritableFontDataPtr wfd;
+    wfd.Attach(WritableFontData::CreateWritableFontData(array_setup_offset[0]));
+    FillTestFontDataWithShortsForSearching(wfd,
+                                           LOWER_BYTE_ARRAY_FOR_SEARCHING,
+                                           array_setup_offset[1],
+                                           array_setup_offset[2],
+                                           UPPER_BYTE_ARRAY_FOR_SEARCHING,
+                                           array_setup_offset[3],
+                                           array_setup_offset[4]);
+    for (int32_t j = 0; j < kSearchTestPairsLength; ++j) {
+      const int32_t* test_case = SEARCH_TEST_PAIRS[j];
+      int32_t found = wfd->SearchUShort(array_setup_offset[1],
+                                        array_setup_offset[2],
+                                        array_setup_offset[3],
+                                        array_setup_offset[4],
+                                        kLowerByteArrayForSearchingLength,
+                                        test_case[0]);
+#if defined (SFNTLY_DEBUG_FONTDATA)
+      fprintf(stderr, "Searching for %d; Got %d; Expected %d; "
+              "[test %d][offset %d]\n",
+              test_case[0], found, test_case[1], j, i);
+#endif
+      EXPECT_EQ(test_case[1], found);
+    }
+  }
+  return true;
+}
 
 void FillTestByteArray(ByteArray* ba, int32_t size) {
   for (int32_t i = 0; i < size; ++i) {
@@ -220,6 +327,10 @@
 
 }  // namespace sfntly
 
+TEST(FontData, ReadableFontDataSearching) {
+  ASSERT_TRUE(sfntly::TestReadableFontDataSearching());
+}
+
 TEST(FontData, All) {
   ASSERT_TRUE(sfntly::TestReadableFontData());
   ASSERT_TRUE(sfntly::TestWritableFontData());