diff options
Diffstat (limited to 'compiler/moco-tf/src/Annotations')
-rw-r--r-- | compiler/moco-tf/src/Annotations/ConcatData.h | 44 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/PadData.h | 51 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/PaddingData.h | 49 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/ShapeInferenceData.cpp | 264 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/ShapeInferenceData.h | 75 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/ShapeInferenceData.test.cpp | 174 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/StrideData.h | 48 | ||||
-rw-r--r-- | compiler/moco-tf/src/Annotations/WindowData.h | 46 |
8 files changed, 751 insertions, 0 deletions
diff --git a/compiler/moco-tf/src/Annotations/ConcatData.h b/compiler/moco-tf/src/Annotations/ConcatData.h new file mode 100644 index 000000000..4c8e5fa5e --- /dev/null +++ b/compiler/moco-tf/src/Annotations/ConcatData.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_CONCAT_DATA_H__ +#define __MOCO_TF_CONCAT_DATA_H__ + +#include <loco.h> + +namespace moco +{ +namespace tf +{ + +/** + * @brief ConcatData holds temporary axis attribute of Concat while building the graph +*/ +class ConcatData : public loco::NodeAnnotation +{ +public: + ConcatData(int32_t axis) : _axis(axis) {} + + int32_t axis(void) const { return _axis; } + +private: + int32_t _axis; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_CONCAT_DATA_H__ diff --git a/compiler/moco-tf/src/Annotations/PadData.h b/compiler/moco-tf/src/Annotations/PadData.h new file mode 100644 index 000000000..887a1c503 --- /dev/null +++ b/compiler/moco-tf/src/Annotations/PadData.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_PAD_DATA_H__ +#define __MOCO_TF_PAD_DATA_H__ + +#include <loco.h> + +namespace moco +{ +namespace tf +{ + +/** + * @brief PadData holds temporary 'pad' attribute of TFConv2D + * + * @note This holds the same pad attribute that exist in Canonical Conv2D + * to simplify Canonicalizing step of TFConv2D to Conv2D conversion. + * Values of 'pad' will be calculated in FixPaddingTransformation. + * PadData holds Padding2D where PaddingData holds 'padding' as a string. + */ +class PadData : public loco::NodeAnnotation +{ +public: + PadData() = default; + +public: + const loco::Padding2D *pad(void) const { return &_pad; } + loco::Padding2D *pad(void) { return &_pad; } + +private: + loco::Padding2D _pad; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_PAD_DATA_H__ diff --git a/compiler/moco-tf/src/Annotations/PaddingData.h b/compiler/moco-tf/src/Annotations/PaddingData.h new file mode 100644 index 000000000..e875cca7d --- /dev/null +++ b/compiler/moco-tf/src/Annotations/PaddingData.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_PADDING_DATA_H__ +#define __MOCO_TF_PADDING_DATA_H__ + +#include <loco.h> + +#include <string> + +namespace moco +{ +namespace tf +{ + +/** + * @brief PaddingData holds temporary padding attribute + * + * @note Related nodes are AvgPool2D, MaxPool2D, Conv2D and maybe others + * PaddingData holds 'padding' as a string where PadData holds Padding2D + */ +class PaddingData : public loco::NodeAnnotation +{ +public: + PaddingData(const std::string &padding) : _padding(padding) {} + + const std::string &padding(void) const { return _padding; } + +private: + std::string _padding; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_PADDING_DATA_H__ diff --git a/compiler/moco-tf/src/Annotations/ShapeInferenceData.cpp b/compiler/moco-tf/src/Annotations/ShapeInferenceData.cpp new file mode 100644 index 000000000..e6ffa98ae --- /dev/null +++ b/compiler/moco-tf/src/Annotations/ShapeInferenceData.cpp @@ -0,0 +1,264 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeInferenceData.h" + +#include <stdexcept> + +namespace moco +{ +namespace tf +{ + +loco::TensorShape ShapeInferenceData::tensor_shape(void) const +{ + assert(_domain == loco::Domain::Tensor); + + loco::TensorShape shape; + + shape.rank(rank()); + for (uint32_t r = 0; r < rank(); ++r) + { + if (dim(r).known()) + shape.dim(r) = dim(r).value(); + else + shape.dim(r).unset(); + } + + return shape; +} + +loco::FeatureShape ShapeInferenceData::feature_shape(void) const +{ + assert(_domain == loco::Domain::Feature); + + loco::FeatureShape shape; + + if (rank() != 4) + throw std::runtime_error("Feature should be rank 4"); + + shape.count() = dim(0); + shape.height() = dim(1); + shape.width() = dim(2); + shape.depth() = dim(3); + + return shape; +} + +loco::FilterShape ShapeInferenceData::filter_shape(void) const +{ + assert(_domain == loco::Domain::Filter); + + loco::FilterShape shape; + + if (rank() != 4) + throw std::runtime_error("Filter should be rank 4"); + + shape.count() = dim(0); + shape.height() = dim(1); + shape.width() = dim(2); + shape.depth() = dim(3); + + return shape; +} + +loco::DepthwiseFilterShape ShapeInferenceData::depthwisefilter_shape(void) const +{ + assert(_domain == loco::Domain::DepthwiseFilter); + + loco::DepthwiseFilterShape shape; + + if (rank() != 4) + throw std::runtime_error("DepthwiseFilter should be rank 4"); + + shape.height() = dim(0); + shape.width() = dim(1); + shape.depth() = dim(2); + shape.multiplier() = dim(3); + + return shape; +} + +loco::BiasShape ShapeInferenceData::bias_shape(void) const +{ + assert(_domain == loco::Domain::Bias); + + loco::BiasShape shape; + + // Note: this may change when loco::BiasShape becomes available + shape.length() = dim(0).value(); + + return shape; +} + +void ShapeInferenceData::tensor_shape(const loco::TensorShape &shape) +{ + _domain = loco::Domain::Tensor; + + rank(shape.rank()); + for (uint32_t r = 0; r < shape.rank(); ++r) + { + if (shape.dim(r).known()) + dim(r) = shape.dim(r).value(); + else + dim(r).unset(); + } +} + +void ShapeInferenceData::feature_shape(const loco::FeatureShape &shape) +{ + _domain = loco::Domain::Feature; + + rank(4); + dim(0) = shape.count(); + dim(1) = shape.height(); + dim(2) = shape.width(); + dim(3) = shape.depth(); +} + +void ShapeInferenceData::filter_shape(const loco::FilterShape &shape) +{ + _domain = loco::Domain::Filter; + + rank(4); + dim(0) = shape.count(); + dim(1) = shape.height(); + dim(2) = shape.width(); + dim(3) = shape.depth(); +} + +void ShapeInferenceData::depthwisefilter_shape(const loco::DepthwiseFilterShape &shape) +{ + _domain = loco::Domain::DepthwiseFilter; + + rank(4); + dim(0) = shape.height(); + dim(1) = shape.width(); + dim(2) = shape.depth(); + dim(3) = shape.multiplier(); +} + +void ShapeInferenceData::bias_shape(const loco::BiasShape &shape) +{ + _domain = loco::Domain::Bias; + + // Note: this may change when loco::BiasShape becomes available + rank(1); + dim(0) = shape.length(); +} + +void as_tensor_shape(ShapeInferenceData &shapedata, const loco::FeatureShape &feature_shape, + const TFDataLayout &data_layout) +{ + loco::TensorShape tensor_shape; + + tensor_shape.rank(4); + if (data_layout == "NHWC") + { + tensor_shape.dim(0) = feature_shape.count(); + tensor_shape.dim(1) = feature_shape.height(); + tensor_shape.dim(2) = feature_shape.width(); + tensor_shape.dim(3) = feature_shape.depth(); + } + else if (data_layout == "NCHW") + { + tensor_shape.dim(0) = feature_shape.count(); + tensor_shape.dim(1) = feature_shape.depth(); + tensor_shape.dim(2) = feature_shape.height(); + tensor_shape.dim(3) = feature_shape.width(); + } + else + { + // TODO support for other data_layout if needed + throw std::runtime_error("as_tensor_shape: only supports NHWC or NCHW"); + } + + shapedata.tensor_shape(tensor_shape); +} + +loco::FeatureShape as_feature_shape(const ShapeInferenceData &shapedata, + const TFDataLayout &data_layout) +{ + if (shapedata.domain() == loco::Domain::Feature) + return shapedata.feature_shape(); + + loco::FeatureShape feature_shape; + + // only convert from tensor to feature + if (shapedata.domain() != loco::Domain::Tensor) + { + throw std::runtime_error("as_feature_shape: domain is not tensor"); + } + if (shapedata.rank() != 4) + { + throw std::runtime_error("as_feature_shape: rank is not 4"); + } + + // TODO support for other data_layout if needed + if (data_layout != "NHWC" && data_layout != "NCHW") + { + throw std::runtime_error("as_feature_shape: only supports NHWC or NCHW"); + } + + if (data_layout == "NHWC") + { + feature_shape.count() = shapedata.dim(0); + feature_shape.height() = shapedata.dim(1); + feature_shape.width() = shapedata.dim(2); + feature_shape.depth() = shapedata.dim(3); + } + else + { + feature_shape.count() = shapedata.dim(0); + feature_shape.depth() = shapedata.dim(1); + feature_shape.height() = shapedata.dim(2); + feature_shape.width() = shapedata.dim(3); + } + + return feature_shape; +} + +bool operator==(const ShapeInferenceData &lhs, const ShapeInferenceData &rhs) +{ + if (lhs.domain() != rhs.domain()) + return false; + + switch (lhs.domain()) + { + case loco::Domain::Tensor: + { + auto lhs_t = lhs.tensor_shape(); + auto rhs_t = rhs.tensor_shape(); + if (lhs_t.rank() != rhs.rank()) + return false; + for (uint32_t axis = 0; axis < lhs_t.rank(); ++axis) + { + if (!(lhs_t.dim(axis) == rhs_t.dim(axis))) + return false; + } + return true; + } + // TODO Support other domains + // case loco::Domain::Feature: + // case loco::Domain::Filter: + // case loco::Domain::Bias: + default: + throw std::runtime_error("Not supported domain for ShapeInferenceData equality"); + } +} + +} // namespace tf +} // namespace moco diff --git a/compiler/moco-tf/src/Annotations/ShapeInferenceData.h b/compiler/moco-tf/src/Annotations/ShapeInferenceData.h new file mode 100644 index 000000000..d48699356 --- /dev/null +++ b/compiler/moco-tf/src/Annotations/ShapeInferenceData.h @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_SHAPEINFERENCE_DATA_H__ +#define __MOCO_TF_SHAPEINFERENCE_DATA_H__ + +#include <loco.h> +#include "loco/IR/BiasShape.h" + +#include <cassert> + +namespace moco +{ +namespace tf +{ + +/// @note Below alias may be introduced as separate class +using TFDataLayout = std::string; + +/** + * @brief ShapeInferenceData provides shape inference data tracking from the start(input) + * + * @note For Feature and Filter, NHWC is used for shape layout + */ +class ShapeInferenceData : public loco::NodeAnnotation, + public loco::NodeMixin<loco::NodeTrait::TensorShape> +{ +public: + ~ShapeInferenceData(){}; + +public: + loco::Domain domain(void) const { return _domain; } + + loco::TensorShape tensor_shape(void) const; + loco::FeatureShape feature_shape(void) const; + loco::FilterShape filter_shape(void) const; + loco::DepthwiseFilterShape depthwisefilter_shape(void) const; + loco::BiasShape bias_shape(void) const; + + void tensor_shape(const loco::TensorShape &shape); + void feature_shape(const loco::FeatureShape &shape); + void filter_shape(const loco::FilterShape &shape); + void depthwisefilter_shape(const loco::DepthwiseFilterShape &shape); + void bias_shape(const loco::BiasShape &shape); + +private: + // TODO set default as Unknown, setting Tensor is to minimize change + loco::Domain _domain{loco::Domain::Tensor}; +}; + +void as_tensor_shape(ShapeInferenceData &shapedata, const loco::FeatureShape &shape, + const TFDataLayout &data_layout); + +loco::FeatureShape as_feature_shape(const ShapeInferenceData &shapedata, + const TFDataLayout &data_layout); + +bool operator==(const ShapeInferenceData &lhs, const ShapeInferenceData &rhs); + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_SHAPEINFERENCE_DATA_H__ diff --git a/compiler/moco-tf/src/Annotations/ShapeInferenceData.test.cpp b/compiler/moco-tf/src/Annotations/ShapeInferenceData.test.cpp new file mode 100644 index 000000000..8b8de535e --- /dev/null +++ b/compiler/moco-tf/src/Annotations/ShapeInferenceData.test.cpp @@ -0,0 +1,174 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ShapeInferenceData.h" + +#include <gtest/gtest.h> + +TEST(TensorFlowImport, shapeinferencedata_tensor_get) +{ + moco::tf::ShapeInferenceData shapedata; + + shapedata.rank(4); + shapedata.dim(0) = 1; + shapedata.dim(1) = 2; + shapedata.dim(2) = 3; + shapedata.dim(3) = 4; + + loco::TensorShape tensor = shapedata.tensor_shape(); + + ASSERT_EQ(tensor.rank(), 4); + ASSERT_EQ(tensor.dim(0), 1); + ASSERT_EQ(tensor.dim(1), 2); + ASSERT_EQ(tensor.dim(2), 3); + ASSERT_EQ(tensor.dim(3), 4); +} + +TEST(TensorFlowImport, shapeinferencedata_feature) +{ + loco::FeatureShape feature_s; + + feature_s.count() = 1; + feature_s.height() = 2; + feature_s.width() = 3; + feature_s.depth() = 4; + + moco::tf::ShapeInferenceData shapedata; + + shapedata.feature_shape(feature_s); + + loco::FeatureShape feature_g = shapedata.feature_shape(); + + ASSERT_EQ(feature_g.count(), 1); + ASSERT_EQ(feature_g.height(), 2); + ASSERT_EQ(feature_g.width(), 3); + ASSERT_EQ(feature_g.depth(), 4); +} + +TEST(TensorFlowImport, shapeinferencedata_filter) +{ + loco::FilterShape filter_s; + + filter_s.count() = 1; + filter_s.height() = 2; + filter_s.width() = 3; + filter_s.depth() = 4; + + moco::tf::ShapeInferenceData shapedata; + + shapedata.filter_shape(filter_s); + + ASSERT_EQ(shapedata.domain(), loco::Domain::Filter); + + loco::FilterShape filter_g = shapedata.filter_shape(); + + ASSERT_EQ(filter_g.count(), 1); + ASSERT_EQ(filter_g.height(), 2); + ASSERT_EQ(filter_g.width(), 3); + ASSERT_EQ(filter_g.depth(), 4); +} + +TEST(TensorFlowImport, shapeinferencedata_bias) +{ + // Note: this may change when loco::BiasShape becomes available + + loco::BiasShape bias_s; + + bias_s.length() = 3; + + moco::tf::ShapeInferenceData shapedata; + + shapedata.bias_shape(bias_s); + + loco::BiasShape bias_g = shapedata.bias_shape(); + + ASSERT_EQ(bias_g.length(), 3); +} + +TEST(TensorFlowImport, shapeinferencedata_as_tensor_set) +{ + loco::FeatureShape feature_s; + + feature_s.count() = 1; + feature_s.height() = 2; + feature_s.width() = 3; + feature_s.depth() = 4; + + moco::tf::ShapeInferenceData shapedata; + + as_tensor_shape(shapedata, feature_s, "NHWC"); + + loco::TensorShape tensor_g; + + tensor_g = shapedata.tensor_shape(); + + ASSERT_EQ(tensor_g.rank(), 4); + ASSERT_EQ(tensor_g.dim(0), 1); + ASSERT_EQ(tensor_g.dim(1), 2); + ASSERT_EQ(tensor_g.dim(2), 3); + ASSERT_EQ(tensor_g.dim(3), 4); +} + +TEST(TensorFlowImport, shapeinferencedata_as_feature) +{ + loco::TensorShape tensor_s; + + tensor_s.rank(4); + tensor_s.dim(0) = 1; + tensor_s.dim(1) = 2; + tensor_s.dim(2) = 3; + tensor_s.dim(3) = 4; + + moco::tf::ShapeInferenceData shapedata; + + shapedata.tensor_shape(tensor_s); + + loco::FeatureShape feature_g = as_feature_shape(shapedata, "NHWC"); + + ASSERT_EQ(feature_g.count(), 1); + ASSERT_EQ(feature_g.height(), 2); + ASSERT_EQ(feature_g.width(), 3); + ASSERT_EQ(feature_g.depth(), 4); +} + +TEST(TensorFlowImport, shapeinferencedata_equality_tensor) +{ + moco::tf::ShapeInferenceData left; + moco::tf::ShapeInferenceData right, wrong1, wrong2; + + left.rank(2); + left.dim(0) = 1; + left.dim(1) = 2; + ASSERT_EQ(left.domain(), loco::Domain::Tensor); + + right.rank(2); + right.dim(0) = 1; + right.dim(1) = 2; + ASSERT_TRUE(left == right); + + wrong1.rank(1); + wrong1.dim(0) = 1; + ASSERT_FALSE(left == wrong1); + + loco::FeatureShape wrong2_f; + wrong2_f.count() = 1; + wrong2_f.depth() = 1; + wrong2_f.height() = 1; + wrong2_f.width() = 1; + + wrong2.feature_shape(wrong2_f); + ASSERT_FALSE(left == wrong2); +} diff --git a/compiler/moco-tf/src/Annotations/StrideData.h b/compiler/moco-tf/src/Annotations/StrideData.h new file mode 100644 index 000000000..fb9a4b304 --- /dev/null +++ b/compiler/moco-tf/src/Annotations/StrideData.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_STRIDE_DATA_H__ +#define __MOCO_TF_STRIDE_DATA_H__ + +#include <loco.h> + +namespace moco +{ +namespace tf +{ + +/** + * @brief StrideData holds temporary 'stride' attribute of TFConv2D, same thing + * like the one in Conv2D used for Canonicalizing TFConv2D to Conv2D. + * 'stride' will be calculated in FixShapeTransformation as for now. + */ +class StrideData : public loco::NodeAnnotation +{ +public: + StrideData() = default; + +public: + const loco::Stride<2> *stride(void) const { return &_stride; } + loco::Stride<2> *stride(void) { return &_stride; } + +private: + loco::Stride<2> _stride; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_STRIDE_DATA_H__ diff --git a/compiler/moco-tf/src/Annotations/WindowData.h b/compiler/moco-tf/src/Annotations/WindowData.h new file mode 100644 index 000000000..8bd962578 --- /dev/null +++ b/compiler/moco-tf/src/Annotations/WindowData.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __MOCO_TF_WINDOW_DATA_H__ +#define __MOCO_TF_WINDOW_DATA_H__ + +#include <loco.h> + +namespace moco +{ +namespace tf +{ + +/** + * @brief WindowData holds temporary 'window' attribute of AvgPool2D, MaxPool2D + */ +class WindowData : public loco::NodeAnnotation +{ +public: + WindowData() = default; + +public: + const loco::Window<2> *window(void) const { return &_window; } + loco::Window<2> *window(void) { return &_window; } + +private: + loco::Window<2> _window; +}; + +} // namespace tf +} // namespace moco + +#endif // __MOCO_TF_WINDOW_DATA_H__ |