nareshmlx/opencv-pr huggingface dataset:
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
TODO: change step_buf to AutoBuffer, test the performance, cache everything inside finalize(), test the performance
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
I think it should be uncommented
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
TODO: cache everything inside finalize(), test the performance
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
We need to simplify(from reader's perspective) allocation of all these buffers somehow
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support
**Review Line:** 473

**Code Changes:**
```diff
+
+        if (!prepare_for_broadcast_op(ninputs + 1, max_ndims, all_type_sizes,
+                                      all_ndims, (const int**)orig_shapes,
+                                      (const size_t**)orig_steps,
+                                      shapes, steps))
+            return;
+
+        nary_forward_impl<T>(
+                f, scale, ninputs, max_ndims, shapes[0], inp, out, (const size_t **) steps, ptrs);
+    }
+
```

Review comment:
RAII should be used for buf, memory leak here
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
I think we might need to add some kind of a workaround so that we know original dimensions of data, otherwise tests fail because we treated shape (2,) as (2,1) instead of (1,2), for example.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
To my understanding, AutoBuffer should be used in functions. If step_buf and others are AutoBuffer and cached inside finalize(), then AutoBuffer instances have to be used across functions.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
That's why there is performance evaluation step - if I'm understanding correctly, we either can cache this, but use vector, or if it's slower, we can just refactor to use autobuffer.
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
An extra variable is added to carry the original dimensions of constants. Once the original dimension is 1 and the input constant has two dimensions and the last dimension of 1, for example (2, 1), then the input constant will be transposed to (1, 2). I would not say this solution is elegant and robust enough, but it may be a suitable one until we have 1-d Mat.
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
I reuse some code from `parseMul` to handle cases of two non-constant inputs, which should help us to pass all tests without disabling any. Once one-dimensional Mat is supported (https://github.com/opencv/opencv/pull/18594), code related to blobs of extra info and the workaround of two non-constant inputs should be deleted. https://github.com/opencv/opencv/blob/b91f173680af92498a8bd2517fc7c524c2eae640/modules/dnn/src/onnx/onnx_importer.cpp#L2290-L2351
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
We'll need to know the exact shapes for Gather layer anyways, if it's possible to do with extra info, but you think it's unjustified. I'm just sad that we'll still use other layers that don't support broadcasting. EDIT: I misread. Can you please share the names of tests that are failing without custom div and mul layers so that I can take a look?
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
In the case of two non-constant input but one of them is one-dimensional, when net.forward() is called, the first time `getMemoryShape()` is called it can get the correct shape, but the second time `getMemoryShape()` is called it will get the wrong shape since we load a one-dimensional tensor of shape [2] as a Mat of shape [2, 1]. This will lead to an error in `findCommonShape()`. In this case, I do not think of a workaround as what I did for `parseElementWise()` because that shape is got in the forward stage.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
I think we keep buf in binary_forward/nary_forward. Tested with vector and finalize(), performances are almost the same.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
Tested with vector in finalize(), performances are almost the same. So we use buf with autobuffer.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
Since we are using buf with autobuffer, I cannot think of a way to simplify the allocation but only make detailed and clear comments to explain the buf.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support
**Review Line:** 473

**Code Changes:**
```diff
+
+        if (!prepare_for_broadcast_op(ninputs + 1, max_ndims, all_type_sizes,
+                                      all_ndims, (const int**)orig_shapes,
+                                      (const size_t**)orig_steps,
+                                      shapes, steps))
+            return;
+
+        nary_forward_impl<T>(
+                f, scale, ninputs, max_ndims, shapes[0], inp, out, (const size_t **) steps, ptrs);
+    }
+
```

Review comment:
Does AutoBuffer solve this problem like what I did?
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support
**Review Line:** 58

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
I think we should keep this perf test. So replaced the for loop value asignment with `cv::randn` which fills the mat with random numbers from standard normal distribution (mean=0 and std=1). And more perf cases are added. See first comment for updated benchmark results.
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support
**Review Line:** 503

**Code Changes:**
```diff
+    template<typename T, typename... Args>
+    inline void opDispatch(size_t ninputs, Args&&... args)
+    {
+        switch (op)
+        {
+            case OPERATION::EQUAL:
+            {
+                auto equal = [](const T &a, const T &b) { return a == b; };
+                binary_forward<T>(equal, std::forward<Args>(args)...);
+                break;
+            }
```

Review comment:
I think we dont do this for now. Some test cases need OPs returning bool (but is casted to non-bool for the next operation), such as `Test_ONNX_layers.Compare_EQ/0`, `Test_ONNX_layers.CompareSameDims_EQ/0` and so on.
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
You fixed test instantiation, so I think this should be uncommented
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
I think we should remove this function(or reuse the third one in both ref and non-ref with bool parameter isRef, that changes which layer we add), so that we avoid code duplication and different input generation between ref and non-ref functions.
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
Might I suggest alternating pattern(non-ref/ref layers) where applicable, so that it's easier to compare the results in the output?
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
I think this is misplaced - NaryEltwiseLayer should support inputs >= 2
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
Can you explain which test-cases does this code enable? I thought we agreed that we will just disable the tests for now?
**File:** modules/dnn/src/layers/nary_eltwise_layers.cpp
**Change Type:** added
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -0,0 +1,664 @@
+// This file is part of OpenCV project.
+// It is subject to the license terms in the LICENSE file found in the top-level directory
+// of this distribution and at http://opencv.org/license.html.
+
+#include "../precomp.hpp"
+#include "layers_common.hpp"
+#include <opencv2/dnn/shape_utils.hpp>
+
+#include <algorithm>
```

Review comment:
should we remove this?
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
Done with reusing with a bool parameter `isRef`.
**File:** modules/dnn/perf/perf_layer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -55,7 +55,156 @@ struct Layer_Slice : public TestBaseWithParam<tuple<Backend, Target> >
     }
 };
 
+struct Layer_NaryEltwise : public TestBaseWithParam<tuple<Backend, Target> >
+{
+    void test_layer(const std::vector<int>& a_shape, const std::vector<int>& b_shape, const String op, bool isRef = false)
+    {
+        int backendId = get<0>(GetParam());
+        int targetId = get<1>(GetParam());
```

Review comment:
Done with putting non-ref and ref layers together. ```cpp PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_div) { test_layer({N, C, H, W}, {N, C, H, W}, "div"); } PERF_TEST_P_(Layer_NaryEltwise, NCHW_NCHW_ref_div) { test_layer({N, C, H, W}, {N, C, H, W}, "div", true); } ```
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
It should, but following lines are analyzing only two inputs. Practically speaking, inputs >=2 is rare. So I think we can focus on broadcasting in this pull request.
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
Let me disable the two tests in ONNX conformance. Done. This piece of code is also removed.
**File:** modules/dnn/src/onnx/onnx_importer.cpp
**Change Type:** modified
**Context:** PR #21865: Reimplementation of Element-wise layers with broadcasting support

**Code Changes:**
```diff
@@ -63,10 +63,17 @@ class ONNXImporter
         LayerInfo(int _layerId = 0, int _outputId = 0) : layerId(_layerId), outputId(_outputId) {}
     };
 
+    struct TensorInfo {
+        int real_ndims;
+        TensorInfo(int _real_ndims = 0) : real_ndims(_real_ndims) {}
+    };
+
     std::map<std::string, Mat> getGraphTensors(
```

Review comment:
1. I think we can remove `else {` and the closing bracket. 2. Would something like this work(not tested)?: ```cpp size_t consts = 0; for (size_t i = 0; i < node_proto.input_size(); ++i) { if (layer_id.find(node_proto.input(i)) == layer_id.end()) { ++consts; } } if (consts == node_proto.input_size()) { std::vector<Mat> inputs, output; for (size_t i = 0; i < node_proto.input_size(); ++i) { inputs.push_back(getBlob(node_proto, i)); } runLayer(layerParams, inputs, output); CV_Assert(output.size() == 1); addConstant(node_proto.output(0), output[0]); return; } else if (consts > 0) { for (size_t i = 0; i < node_proto.input_size(); ++i) { if (layer_id.find(node_proto.input(i)) == layer_id.end()) { Mat inp = getBlob(node_proto, i); // for cases like a tensor of shape (2,), it will be loaded as shape (2, 1) in OpenCV Mat, // but for correct broadcast, we need to make it of shape (1, 2) if (constBlobsExtraInfo.find(node_proto.input(i)) != constBlobsExtraInfo.end()) pre_broadcast_transform(inp, getBlobExtraInfo(node_proto, i).real_ndims); // carry the constant by adding a Const node LayerParams constParams; constParams.name = node_proto.input(i); constParams.type = "Const"; constParams.blobs.push_back(inp); opencv_onnx::NodeProto proto; proto.add_output(constParams.name); addLayer(constParams, proto); } } } ```
**File:** modules/objdetect/src/haar.cpp
**Change Type:** modified
**Context:** PR #8940: batch-oriented mutex locking in haar detector parallel loop body - ### This pullrequest changes In haar detector parallel loop body insertio...
**Review Line:** 1539

**Code Changes:**
```diff
                 }
                 ixstep = result != 0 ? 1 : 2;
             }
         }
+
+        if (vecLocal.size())
+        {
+            mtx->lock();
+            vec->insert(vec->end(), vecLocal.begin(), vecLocal.end());
+            mtx->unlock();
+        }
```

Review comment:
implicit conversion of size_t to bool is fine in C/C++, but it would be more stylish to use `!vecLocal.empty()` instead
**File:** modules/python/src2/gen2.py
**Change Type:** modified
**Context:** PR #23268: fix: remove extra '/O' modifier for '/IO' arguments

**Code Changes:**
```diff
@@ -448,6 +448,15 @@ def __init__(self, atype, name, default_value, modifiers=(),
         self.py_outputarg = False
         self.enclosing_arg = enclosing_arg
 
+    def __str__(self):
+        return 'ArgInfo("{}", tp="{}", default="{}", in={}, out={})'.format(
+            self.name, self.tp, self.defval, self.inputarg,
+            self.outputarg
+        )
+
```

Review comment:
Should this be done in hdr_parser.py instead?