[ulib][zircon] Use template functions in zx_cache_flush

This reduces the repeated boilerplate loop code in the source but
still compiles down to the same thing as the old code.

Change-Id: Ib4f29f4e6c3da9235cd95a0ed69ca06f003cdf4d
diff --git a/system/ulib/zircon/zx_cache_flush.cpp b/system/ulib/zircon/zx_cache_flush.cpp
index eb2d2ef..5bc6748 100644
--- a/system/ulib/zircon/zx_cache_flush.cpp
+++ b/system/ulib/zircon/zx_cache_flush.cpp
@@ -7,6 +7,30 @@
 #include <zircon/compiler.h>
 #include "private.h"
 
+namespace {
+
+template<typename T>
+void for_each_cache_line(const void* addr, size_t len, uint32_t line_size,
+                         T func) {
+    for (uintptr_t p = (uintptr_t)addr & -(uintptr_t)line_size;
+         p < (uintptr_t)addr + len;
+         p += line_size) {
+        func(p);
+    }
+}
+
+template<typename T>
+void for_each_dcache_line(const void* addr, size_t len, T func) {
+    for_each_cache_line(addr, len, DATA_CONSTANTS.dcache_line_size, func);
+}
+
+template<typename T>
+void for_each_icache_line(const void* addr, size_t len, T func) {
+    for_each_cache_line(addr, len, DATA_CONSTANTS.icache_line_size, func);
+}
+
+}  // anonymous namespace
+
 zx_status_t _zx_cache_flush(const void* addr, size_t len, uint32_t flags) {
     if (flags == 0 || (flags & ~(ZX_CACHE_FLUSH_INSN | ZX_CACHE_FLUSH_DATA)))
         return ZX_ERR_INVALID_ARGS;
@@ -18,37 +42,28 @@
 #elif defined(__aarch64__)
 
     if (flags & ZX_CACHE_FLUSH_DATA) {
-        for (uintptr_t p = ((uintptr_t)addr &
-                            -((uintptr_t)DATA_CONSTANTS.dcache_line_size));
-             p < (uintptr_t)addr + len;
-             p += DATA_CONSTANTS.dcache_line_size) {
-            // Clean data cache (dc) to point of coherency (cvac).
-            __asm__ volatile("dc cvac, %0" :: "r"(p));
-        }
+        for_each_dcache_line(addr, len, [](uintptr_t p) {
+                // Clean data cache (dc) to point of coherency (cvac).
+                __asm__ volatile("dc cvac, %0" :: "r"(p));
+            });
     }
 
     if (flags & ZX_CACHE_FLUSH_INSN) {
         // If we didn't already clean the dcache all the way to the point
         // of coherency, clean it the point to unification.
         if (!(flags & ZX_CACHE_FLUSH_DATA)) {
-            for (uintptr_t p = ((uintptr_t)addr &
-                                -((uintptr_t)DATA_CONSTANTS.dcache_line_size));
-                 p < (uintptr_t)addr + len;
-                 p += DATA_CONSTANTS.dcache_line_size) {
-                // Clean data cache (dc) to point of unification (cvau).
-                __asm__ volatile("dc cvau, %0" :: "r"(p));
-            }
+            for_each_dcache_line(addr, len, [](uintptr_t p) {
+                    // Clean data cache (dc) to point of unification (cvau).
+                    __asm__ volatile("dc cvau, %0" :: "r"(p));
+                });
         }
         // Synchronize the dcache flush to before the icache flush.
         __asm__ volatile("dsb ish");
 
-        for (uintptr_t p = ((uintptr_t)addr &
-                            -((uintptr_t)DATA_CONSTANTS.icache_line_size));
-             p < (uintptr_t)addr + len;
-             p += DATA_CONSTANTS.icache_line_size) {
-            // Clean instruction cache (ic) to point of unification (ivau).
-            __asm__ volatile("ic ivau, %0" :: "r"(p));
-        }
+        for_each_icache_line(addr, len, [](uintptr_t p) {
+                // Clean instruction cache (ic) to point of unification (ivau).
+                __asm__ volatile("ic ivau, %0" :: "r"(p));
+            });
         // Synchronize the icache flush to before future instruction fetches.
         __asm__ volatile("isb sy");
     }