diff options
Diffstat (limited to '')
| -rw-r--r-- | src/core/hle/service/cmif_serialization.h | 65 |
1 files changed, 32 insertions, 33 deletions
diff --git a/src/core/hle/service/cmif_serialization.h b/src/core/hle/service/cmif_serialization.h index 84b736155..9eb10e816 100644 --- a/src/core/hle/service/cmif_serialization.h +++ b/src/core/hle/service/cmif_serialization.h | |||
| @@ -97,20 +97,20 @@ constexpr RequestLayout GetDomainReplyOutLayout() { | |||
| 97 | }; | 97 | }; |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | template <bool Domain, typename MethodArguments> | 100 | template <typename MethodArguments> |
| 101 | constexpr RequestLayout GetReplyInLayout() { | 101 | constexpr RequestLayout GetReplyInLayout(bool is_domain) { |
| 102 | return Domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); | 102 | return is_domain ? GetDomainReplyInLayout<MethodArguments>() : GetNonDomainReplyInLayout<MethodArguments>(); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | template <bool Domain, typename MethodArguments> | 105 | template <typename MethodArguments> |
| 106 | constexpr RequestLayout GetReplyOutLayout() { | 106 | constexpr RequestLayout GetReplyOutLayout(bool is_domain) { |
| 107 | return Domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); | 107 | return is_domain ? GetDomainReplyOutLayout<MethodArguments>() : GetNonDomainReplyOutLayout<MethodArguments>(); |
| 108 | } | 108 | } |
| 109 | 109 | ||
| 110 | using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; | 110 | using OutTemporaryBuffers = std::array<Common::ScratchBuffer<u8>, 3>; |
| 111 | 111 | ||
| 112 | template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> | 112 | template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t HandleIndex = 0, size_t InBufferIndex = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> |
| 113 | void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { | 113 | void ReadInArgument(bool is_domain, CallArguments& args, const u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { |
| 114 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { | 114 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { |
| 115 | return; | 115 | return; |
| 116 | } else { | 116 | } else { |
| @@ -134,25 +134,25 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& | |||
| 134 | std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); | 134 | std::memcpy(&std::get<ArgIndex>(args), raw_data + ArgOffset, ArgSize); |
| 135 | } | 135 | } |
| 136 | 136 | ||
| 137 | return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); | 137 | return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 138 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { | 138 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InInterface) { |
| 139 | constexpr size_t ArgAlign = alignof(u32); | 139 | constexpr size_t ArgAlign = alignof(u32); |
| 140 | constexpr size_t ArgSize = sizeof(u32); | 140 | constexpr size_t ArgSize = sizeof(u32); |
| 141 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); | 141 | constexpr size_t ArgOffset = Common::AlignUp(DataOffset, ArgAlign); |
| 142 | constexpr size_t ArgEnd = ArgOffset + ArgSize; | 142 | constexpr size_t ArgEnd = ArgOffset + ArgSize; |
| 143 | 143 | ||
| 144 | static_assert(Domain); | 144 | ASSERT(is_domain); |
| 145 | ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); | 145 | ASSERT(ctx.GetDomainMessageHeader().input_object_count > 0); |
| 146 | 146 | ||
| 147 | u32 value{}; | 147 | u32 value{}; |
| 148 | std::memcpy(&value, raw_data + ArgOffset, ArgSize); | 148 | std::memcpy(&value, raw_data + ArgOffset, ArgSize); |
| 149 | std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); | 149 | std::get<ArgIndex>(args) = ctx.GetDomainHandler<ArgType::Type>(value - 1); |
| 150 | 150 | ||
| 151 | return ReadInArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); | 151 | return ReadInArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, HandleIndex, InBufferIndex, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 152 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { | 152 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InCopyHandle) { |
| 153 | std::get<ArgIndex>(args) = ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)).GetPointerUnsafe(); | 153 | std::get<ArgIndex>(args) = ctx.GetObjectFromHandle<typename ArgType::Type>(ctx.GetCopyHandle(HandleIndex)).GetPointerUnsafe(); |
| 154 | 154 | ||
| 155 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 155 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex + 1, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 156 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { | 156 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InLargeData) { |
| 157 | constexpr size_t BufferSize = sizeof(ArgType); | 157 | constexpr size_t BufferSize = sizeof(ArgType); |
| 158 | 158 | ||
| @@ -172,7 +172,7 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& | |||
| 172 | 172 | ||
| 173 | std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); | 173 | std::memcpy(&std::get<ArgIndex>(args), buffer.data(), std::min(BufferSize, buffer.size())); |
| 174 | 174 | ||
| 175 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 175 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 176 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { | 176 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::InBuffer) { |
| 177 | using ElementType = typename ArgType::Type; | 177 | using ElementType = typename ArgType::Type; |
| 178 | 178 | ||
| @@ -193,14 +193,14 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& | |||
| 193 | 193 | ||
| 194 | std::get<ArgIndex>(args) = std::span(ptr, size); | 194 | std::get<ArgIndex>(args) = std::span(ptr, size); |
| 195 | 195 | ||
| 196 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 196 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex + 1, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 197 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { | 197 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { |
| 198 | constexpr size_t BufferSize = sizeof(ArgType); | 198 | constexpr size_t BufferSize = sizeof(ArgType); |
| 199 | 199 | ||
| 200 | // Clear the existing data. | 200 | // Clear the existing data. |
| 201 | std::memset(&std::get<ArgIndex>(args), 0, BufferSize); | 201 | std::memset(&std::get<ArgIndex>(args), 0, BufferSize); |
| 202 | 202 | ||
| 203 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 203 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 204 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { | 204 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { |
| 205 | using ElementType = typename ArgType::Type; | 205 | using ElementType = typename ArgType::Type; |
| 206 | 206 | ||
| @@ -217,15 +217,15 @@ void ReadInArgument(CallArguments& args, const u8* raw_data, HLERequestContext& | |||
| 217 | 217 | ||
| 218 | std::get<ArgIndex>(args) = std::span(ptr, size); | 218 | std::get<ArgIndex>(args) = std::span(ptr, size); |
| 219 | 219 | ||
| 220 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 220 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 221 | } else { | 221 | } else { |
| 222 | return ReadInArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 222 | return ReadInArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, HandleIndex, InBufferIndex, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 223 | } | 223 | } |
| 224 | } | 224 | } |
| 225 | } | 225 | } |
| 226 | 226 | ||
| 227 | template <bool Domain, typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> | 227 | template <typename MethodArguments, typename CallArguments, size_t PrevAlign = 1, size_t DataOffset = 0, size_t OutBufferIndex = 0, bool RawDataFinished = false, size_t ArgIndex = 0> |
| 228 | void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { | 228 | void WriteOutArgument(bool is_domain, CallArguments& args, u8* raw_data, HLERequestContext& ctx, OutTemporaryBuffers& temp) { |
| 229 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { | 229 | if constexpr (ArgIndex >= std::tuple_size_v<CallArguments>) { |
| 230 | return; | 230 | return; |
| 231 | } else { | 231 | } else { |
| @@ -243,23 +243,23 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, | |||
| 243 | 243 | ||
| 244 | std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); | 244 | std::memcpy(raw_data + ArgOffset, &std::get<ArgIndex>(args), ArgSize); |
| 245 | 245 | ||
| 246 | return WriteOutArgument<Domain, MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(args, raw_data, ctx, temp); | 246 | return WriteOutArgument<MethodArguments, CallArguments, ArgAlign, ArgEnd, OutBufferIndex, false, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 247 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { | 247 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutInterface) { |
| 248 | if constexpr (Domain) { | 248 | if (is_domain) { |
| 249 | ctx.AddDomainObject(std::get<ArgIndex>(args)); | 249 | ctx.AddDomainObject(std::get<ArgIndex>(args)); |
| 250 | } else { | 250 | } else { |
| 251 | ctx.AddMoveInterface(std::get<ArgIndex>(args)); | 251 | ctx.AddMoveInterface(std::get<ArgIndex>(args)); |
| 252 | } | 252 | } |
| 253 | 253 | ||
| 254 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(args, raw_data, ctx, temp); | 254 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, true, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 255 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { | 255 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutCopyHandle) { |
| 256 | ctx.AddCopyObject(std::get<ArgIndex>(args)); | 256 | ctx.AddCopyObject(std::get<ArgIndex>(args)); |
| 257 | 257 | ||
| 258 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 258 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 259 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { | 259 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutMoveHandle) { |
| 260 | ctx.AddMoveObject(std::get<ArgIndex>(args)); | 260 | ctx.AddMoveObject(std::get<ArgIndex>(args)); |
| 261 | 261 | ||
| 262 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 262 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 263 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { | 263 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutLargeData) { |
| 264 | constexpr size_t BufferSize = sizeof(ArgType); | 264 | constexpr size_t BufferSize = sizeof(ArgType); |
| 265 | 265 | ||
| @@ -272,7 +272,7 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, | |||
| 272 | ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); | 272 | ctx.WriteBufferC(&std::get<ArgIndex>(args), BufferSize, OutBufferIndex); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 275 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 276 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { | 276 | } else if constexpr (ArgumentTraits<ArgType>::Type == ArgumentType::OutBuffer) { |
| 277 | auto& buffer = temp[OutBufferIndex]; | 277 | auto& buffer = temp[OutBufferIndex]; |
| 278 | const size_t size = buffer.size(); | 278 | const size_t size = buffer.size(); |
| @@ -287,9 +287,9 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, | |||
| 287 | } | 287 | } |
| 288 | } | 288 | } |
| 289 | 289 | ||
| 290 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>( args, raw_data, ctx, temp); | 290 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex + 1, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 291 | } else { | 291 | } else { |
| 292 | return WriteOutArgument<Domain, MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(args, raw_data, ctx, temp); | 292 | return WriteOutArgument<MethodArguments, CallArguments, PrevAlign, DataOffset, OutBufferIndex, RawDataFinished, ArgIndex + 1>(is_domain, args, raw_data, ctx, temp); |
| 293 | } | 293 | } |
| 294 | } | 294 | } |
| 295 | } | 295 | } |
| @@ -297,11 +297,10 @@ void WriteOutArgument(CallArguments& args, u8* raw_data, HLERequestContext& ctx, | |||
| 297 | template <bool Domain, typename T, typename... A> | 297 | template <bool Domain, typename T, typename... A> |
| 298 | void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { | 298 | void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { |
| 299 | // Verify domain state. | 299 | // Verify domain state. |
| 300 | if constexpr (Domain) { | 300 | if constexpr (!Domain) { |
| 301 | ASSERT_MSG(ctx.GetManager()->IsDomain(), "Domain reply used on non-domain session"); | ||
| 302 | } else { | ||
| 303 | ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); | 301 | ASSERT_MSG(!ctx.GetManager()->IsDomain(), "Non-domain reply used on domain session"); |
| 304 | } | 302 | } |
| 303 | const bool is_domain = Domain ? ctx.GetManager()->IsDomain() : false; | ||
| 305 | 304 | ||
| 306 | using MethodArguments = std::tuple<std::remove_reference_t<A>...>; | 305 | using MethodArguments = std::tuple<std::remove_reference_t<A>...>; |
| 307 | 306 | ||
| @@ -310,7 +309,7 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { | |||
| 310 | 309 | ||
| 311 | // Read inputs. | 310 | // Read inputs. |
| 312 | const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; | 311 | const size_t offset_plus_command_id = ctx.GetDataPayloadOffset() + 2; |
| 313 | ReadInArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); | 312 | ReadInArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + offset_plus_command_id), ctx, buffers); |
| 314 | 313 | ||
| 315 | // Call. | 314 | // Call. |
| 316 | const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { | 315 | const auto Callable = [&]<typename... CallArgs>(CallArgs&... args) { |
| @@ -319,12 +318,12 @@ void CmifReplyWrapImpl(HLERequestContext& ctx, T& t, Result (T::*f)(A...)) { | |||
| 319 | const Result res = std::apply(Callable, call_arguments); | 318 | const Result res = std::apply(Callable, call_arguments); |
| 320 | 319 | ||
| 321 | // Write result. | 320 | // Write result. |
| 322 | constexpr RequestLayout layout = GetReplyOutLayout<Domain, MethodArguments>(); | 321 | const RequestLayout layout = GetReplyOutLayout<MethodArguments>(is_domain); |
| 323 | IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count}; | 322 | IPC::ResponseBuilder rb{ctx, 2 + Common::DivCeil(layout.cmif_raw_data_size, sizeof(u32)), layout.copy_handle_count, layout.move_handle_count + layout.domain_interface_count}; |
| 324 | rb.Push(res); | 323 | rb.Push(res); |
| 325 | 324 | ||
| 326 | // Write out arguments. | 325 | // Write out arguments. |
| 327 | WriteOutArgument<Domain, MethodArguments>(call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); | 326 | WriteOutArgument<MethodArguments>(is_domain, call_arguments, reinterpret_cast<u8*>(ctx.CommandBuffer() + rb.GetCurrentOffset()), ctx, buffers); |
| 328 | } | 327 | } |
| 329 | // clang-format on | 328 | // clang-format on |
| 330 | 329 | ||