COMPMID-3069: Improve compilation time by removing regex from test framework headers

Regex is used as an implementation detail by TestFilter and libnpy,
is an expensive header to parse, and also instantiates static objects.

Move TestFilter out of Framework.h by using a partial definition and
a unique_ptr instead of storing the TestFilter by value.

Move npy.h out of AssetsLibrary.h by moving part of a template
definition into AssetsLibrary.cpp

Knocks about 15% off compilation time of small test cases (for me,
knocked .7s off 5s compilation of HogDetector.cpp)

Signed-off-by: Matthew Bentham <matthew.bentham@arm.com>
Change-Id: I1dce18855d0752ec25b2165fddbc6861a4c55a76
Reviewed-on: https://eu-gerrit-1.euhpc.arm.com/c/VisualCompute/ComputeLibrary/+/229181
Reviewed-by: Georgios Pinitas <georgios.pinitas@arm.com>
Tested-by: bsgcomp <bsgcomp@arm.com>
Reviewed-on: https://review.mlplatform.org/c/ml/ComputeLibrary/+/2856
Tested-by: Arm Jenkins <bsgcomp@arm.com>
Comments-Addressed: Arm Jenkins <bsgcomp@arm.com>
Reviewed-by: Michele Di Giorgio <michele.digiorgio@arm.com>
diff --git a/tests/AssetsLibrary.cpp b/tests/AssetsLibrary.cpp
index c6d86d1..eafa631 100644
--- a/tests/AssetsLibrary.cpp
+++ b/tests/AssetsLibrary.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017-2018 ARM Limited.
+ * Copyright (c) 2017-2020 ARM Limited.
  *
  * SPDX-License-Identifier: MIT
  *
@@ -28,6 +28,11 @@
 
 #include "arm_compute/core/ITensor.h"
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-parameter"
+#include "libnpy/npy.hpp"
+#pragma GCC diagnostic pop
+
 #include <cctype>
 #include <fstream>
 #include <limits>
@@ -511,5 +516,42 @@
 {
     return RawTensor(find_or_create_raw_tensor(name, format, channel));
 }
+
+namespace detail
+{
+inline void validate_npy_header(std::ifstream &stream, const std::string &expect_typestr, const TensorShape &expect_shape)
+{
+    ARM_COMPUTE_UNUSED(expect_typestr);
+    ARM_COMPUTE_UNUSED(expect_shape);
+
+    std::string header = npy::read_header(stream);
+
+    // Parse header
+    std::vector<unsigned long> shape;
+    bool                       fortran_order = false;
+    std::string                typestr;
+    npy::parse_header(header, typestr, fortran_order, shape);
+
+    // Check if the typestring matches the given one
+    ARM_COMPUTE_ERROR_ON_MSG(typestr != expect_typestr, "Typestrings mismatch");
+
+    // Validate tensor shape
+    ARM_COMPUTE_ERROR_ON_MSG(shape.size() != expect_shape.num_dimensions(), "Tensor ranks mismatch");
+    if(fortran_order)
+    {
+        for(size_t i = 0; i < shape.size(); ++i)
+        {
+            ARM_COMPUTE_ERROR_ON_MSG(expect_shape[i] != shape[i], "Tensor dimensions mismatch");
+        }
+    }
+    else
+    {
+        for(size_t i = 0; i < shape.size(); ++i)
+        {
+            ARM_COMPUTE_ERROR_ON_MSG(expect_shape[i] != shape[shape.size() - i - 1], "Tensor dimensions mismatch");
+        }
+    }
+}
+} // namespace detail
 } // namespace test
 } // namespace arm_compute