commit 935015fcd0654d5a7f7b6206f62a7b8c9060ad20
Author: dsorber <david.sorber@gmail.com>
Date:   Sat Sep 9 17:39:35 2017 -0400

    Adding example "lowercase util" that tests multiple approaches to lowercasing an entire buffer.

diff --git a/software/lowercase_util/Makefile b/software/lowercase_util/Makefile
new file mode 100644
index 0000000..272ff27
--- /dev/null
+++ b/software/lowercase_util/Makefile
@@ -0,0 +1,13 @@
+
+CXXFLAGS= -std=c++11 -O3
+
+all: main
+
+main: lowercase_util.cc
+	g++ $(CXXFLAGS) lowercase_util.cc -o lowercase_util
+
+#%.o : %.c %.h
+#	g++ $(CXXFLAGS) -c $<
+
+clean:
+	rm -f lowercase_util
diff --git a/software/lowercase_util/lowercase_util.cc b/software/lowercase_util/lowercase_util.cc
new file mode 100644
index 0000000..622ab7c
--- /dev/null
+++ b/software/lowercase_util/lowercase_util.cc
@@ -0,0 +1,139 @@
+
+#include <cctype>
+#include <chrono>
+#include <cstdint>
+#include <fstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+// https://stackoverflow.com/questions/3883993/how-could-these-case-conversion-functions-be-improved
+
+// g++ -std=c++11 -O3 lowercase_util.cc -o lowercase_util
+int main(const int argc, char** argv)
+{
+    if (argc < 2)
+    {
+        std::cerr << "USAGE: " << argv[0] << " <filename>" << std::endl;
+        return -1;
+    }
+    std::cout << "Lowercase Test Util\n" << std::endl;
+    
+    
+    std::string filePath(argv[1]);
+
+    // Stat the file path to get its size
+    struct stat fs_stat;
+    const int gotStatOK(stat(filePath.c_str(), &fs_stat));
+    if (gotStatOK < 0)
+    {
+        perror("stat()");
+        return -1;
+    }
+
+    uint32_t fileSize = fs_stat.st_size;
+    std::cout << "File size: " << fileSize << "\n" << std::endl;
+    
+    // Read in file
+    std::ifstream inFileStream(filePath, std::ios::in | std::ios::binary);
+    if (! inFileStream)
+    {
+        std::cerr << "Unable to open specified file." << std::endl;
+        return -1;
+    }
+    
+    // Read file in then close stream
+    std::vector<char> contents;
+    contents.resize(fileSize);
+    inFileStream.read(contents.data(), fileSize);
+    inFileStream.close();
+    
+    // TEST1: regular tolower() -----------------------------------------------
+    std::vector<char> copy1(contents);
+    
+    auto start = std::chrono::system_clock::now();
+    
+    for (uint32_t idx = 0; idx < fileSize; ++idx)
+    {
+        copy1[idx] = tolower(copy1[idx]);
+    }
+    
+    auto end = std::chrono::system_clock::now();
+    auto diff = end - start;
+    std::cout << "Test 1 -- duration: " 
+              << std::chrono::duration<double, std::milli>(diff).count() 
+              << " ms" << std::endl;
+    
+    // TEST2: technique 1 -----------------------------------------------------
+    std::vector<char> copy2(contents);
+    
+    start = std::chrono::system_clock::now();
+    
+    for (uint32_t idx = 0; idx < fileSize; ++idx)
+    {
+        // *c += (*c - 'A' < 26U) << 5;
+        copy2[idx] += (copy2[idx] - 'A' < 26U) << 5;
+    }
+    
+    end = std::chrono::system_clock::now();
+    diff = end - start;
+    std::cout << "Test 2 -- duration: " 
+              << std::chrono::duration<double, std::milli>(diff).count() 
+              << " ms" << std::endl;
+    
+    #if 0
+    // Verify copy2
+    std::ofstream outStream1("output_copy2.txt", std::ios::out | std::ios::binary);
+    outStream1.write(copy2.data(), fileSize);
+    outStream1.close();
+    #endif
+    
+    
+    // TEST3: technque 2 ------------------------------------------------------
+    std::vector<char> copy3(contents);
+    
+    start = std::chrono::system_clock::now();
+    
+    for (uint32_t idx = 0; idx < fileSize; ++idx)
+    {
+        // *c += (64U - *c & *c - 91U) >> CHAR_BIT * sizeof(unsigned) - 1 << 5;
+        // *c += ((64U - *c & *c - 91U) >> 31) << 5;
+        copy3[idx] += ((64U - copy3[idx] & copy3[idx] - 91U) >> 31) << 5;
+    }
+    
+    end = std::chrono::system_clock::now();
+    diff = end - start;
+    std::cout << "Test 3 -- duration: " 
+              << std::chrono::duration<double, std::milli>(diff).count() 
+              << " ms" << std::endl;
+    
+    #if 0
+    // Verify copy3
+    std::ofstream outStream2("output_copy3.txt", std::ios::out | std::ios::binary);
+    outStream2.write(copy3.data(), fileSize);
+    outStream2.close();
+    #endif
+    
+    
+    // TEST 4: technique 3 ----------------------------------------------------
+    std::vector<char> copy4(contents);
+    
+    start = std::chrono::system_clock::now();
+    
+    for (uint32_t idx = 0; idx < fileSize; ++idx)
+    {
+        // c += (((96-(int)c)&((int)c-123))>>9)&(-32);
+        copy4[idx] += (((96 - (int)copy4[idx]) & ((int)copy4[idx] - 123)) >> 9) & (-32);
+    }
+    
+    end = std::chrono::system_clock::now();
+    diff = end - start;
+    std::cout << "Test 4 -- duration: " 
+              << std::chrono::duration<double, std::milli>(diff).count() 
+              << " ms" << std::endl;
+    
+    return 0;
+}
