Skip to content

Commit 6c79f57

Browse files
committed
Flatten assign op calls
1 parent 3b206e7 commit 6c79f57

File tree

5 files changed

+79
-75
lines changed

5 files changed

+79
-75
lines changed

.gitignore

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,15 @@ librapid/bindings/python/generated
3434
dist/
3535

3636
*.pyc
37+
examples/CMakeFiles
38+
examples/CTestTestfile.cmake
39+
examples/Makefile
40+
examples/cmake_install.cmake
41+
test/CMakeFiles
42+
test/CTestTestfile.cmake
43+
test/Makefile
44+
test/cmake_install.cmake
45+
cmake_install.cmake
46+
DartConfiguration.tcl
47+
CTestTestfile.cmake
48+
Makefile

librapid/include/librapid/array/assignOps.hpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ namespace librapid {
1717
template<typename ShapeType_, typename StorageScalar, typename Functor_, typename... Args>
1818
requires(!typetraits::HasCustomEval<
1919
detail::Function<descriptor::Trivial, Functor_, Args...>>::value)
20-
LIBRAPID_ALWAYS_INLINE void
20+
LIBRAPID_FLATTEN LIBRAPID_ALWAYS_INLINE void
2121
assign(array::ArrayContainer<ShapeType_, Storage<StorageScalar>> &lhs,
2222
const detail::Function<descriptor::Trivial, Functor_, Args...> &function) {
2323
using Function = detail::Function<descriptor::Trivial, Functor_, Args...>;
@@ -75,7 +75,7 @@ namespace librapid {
7575
typename Functor_, typename... Args>
7676
requires(!typetraits::HasCustomEval<
7777
detail::Function<descriptor::Trivial, Functor_, Args...>>::value)
78-
LIBRAPID_ALWAYS_INLINE void
78+
LIBRAPID_FLATTEN LIBRAPID_ALWAYS_INLINE void
7979
assign(array::ArrayContainer<ShapeType_, FixedStorage<StorageScalar, StorageSize...>> &lhs,
8080
const detail::Function<descriptor::Trivial, Functor_, Args...> &function) {
8181
using Function = detail::Function<descriptor::Trivial, Functor_, Args...>;
@@ -137,7 +137,7 @@ namespace librapid {
137137
template<typename ShapeType_, typename StorageScalar, typename Functor_, typename... Args>
138138
requires(!typetraits::HasCustomEval<
139139
detail::Function<descriptor::Trivial, Functor_, Args...>>::value)
140-
LIBRAPID_ALWAYS_INLINE void
140+
LIBRAPID_FLATTEN LIBRAPID_ALWAYS_INLINE void
141141
assignParallel(array::ArrayContainer<ShapeType_, Storage<StorageScalar>> &lhs,
142142
const detail::Function<descriptor::Trivial, Functor_, Args...> &function) {
143143
using Function = detail::Function<descriptor::Trivial, Functor_, Args...>;
@@ -201,7 +201,7 @@ namespace librapid {
201201
typename Functor_, typename... Args>
202202
requires(!typetraits::HasCustomEval<
203203
detail::Function<descriptor::Trivial, Functor_, Args...>>::value)
204-
LIBRAPID_ALWAYS_INLINE void assignParallel(
204+
LIBRAPID_FLATTEN LIBRAPID_ALWAYS_INLINE void assignParallel(
205205
array::ArrayContainer<ShapeType_, FixedStorage<StorageScalar, StorageSize...>> &lhs,
206206
const detail::Function<descriptor::Trivial, Functor_, Args...> &function) {
207207
using Function = detail::Function<descriptor::Trivial, Functor_, Args...>;
@@ -356,7 +356,7 @@ namespace librapid {
356356
namespace cuda {
357357
template<typename T>
358358
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto dataSourceExtractor(const T &obj) {
359-
if constexpr(typetraits::TypeInfo<T>::type ==
359+
if constexpr (typetraits::TypeInfo<T>::type ==
360360
::librapid::detail::LibRapidType::Scalar) {
361361
return obj;
362362
} else {
@@ -545,8 +545,8 @@ namespace librapid {
545545
reinterpret_cast<Scalar *>(lhs.storage().begin()),
546546
function);
547547
}
548-
} // namespace detail
548+
} // namespace detail
549549
#endif // LIBRAPID_HAS_CUDA
550550
} // namespace librapid
551551

552-
#endif // LIBRAPID_ARRAY_ASSIGN_OPS_HPP
552+
#endif // LIBRAPID_ARRAY_ASSIGN_OPS_HPP

librapid/include/librapid/array/operations.hpp

Lines changed: 47 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -943,8 +943,8 @@ namespace librapid {
943943
/// \return Sine function object
944944
template<class VAL>
945945
requires(detail::IsArrayOp<VAL>)
946-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sin(VAL &&val)
947-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sin, VAL> {
946+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
947+
sin(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sin, VAL> {
948948
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sin>(
949949
std::forward<VAL>(val));
950950
}
@@ -958,8 +958,8 @@ namespace librapid {
958958
/// \return Cosine function object
959959
template<class VAL>
960960
requires(detail::IsArrayOp<VAL>)
961-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cos(VAL &&val)
962-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cos, VAL> {
961+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
962+
cos(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cos, VAL> {
963963
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cos>(
964964
std::forward<VAL>(val));
965965
}
@@ -973,8 +973,8 @@ namespace librapid {
973973
/// \return Tangent function object
974974
template<class VAL>
975975
requires(detail::IsArrayOp<VAL>)
976-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto tan(VAL &&val)
977-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tan, VAL> {
976+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
977+
tan(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tan, VAL> {
978978
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Tan>(
979979
std::forward<VAL>(val));
980980
}
@@ -988,8 +988,8 @@ namespace librapid {
988988
/// \return Arcsine function object
989989
template<class VAL>
990990
requires(detail::IsArrayOp<VAL>)
991-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto asin(VAL &&val)
992-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Asin, VAL> {
991+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
992+
asin(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Asin, VAL> {
993993
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Asin>(
994994
std::forward<VAL>(val));
995995
}
@@ -1003,8 +1003,8 @@ namespace librapid {
10031003
/// \return Arccosine function object
10041004
template<class VAL>
10051005
requires(detail::IsArrayOp<VAL>)
1006-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto acos(VAL &&val)
1007-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Acos, VAL> {
1006+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1007+
acos(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Acos, VAL> {
10081008
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Acos>(
10091009
std::forward<VAL>(val));
10101010
}
@@ -1018,8 +1018,8 @@ namespace librapid {
10181018
/// \return Arctangent function object
10191019
template<class VAL>
10201020
requires(detail::IsArrayOp<VAL>)
1021-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto atan(VAL &&val)
1022-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Atan, VAL> {
1021+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1022+
atan(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Atan, VAL> {
10231023
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Atan>(
10241024
std::forward<VAL>(val));
10251025
}
@@ -1033,8 +1033,8 @@ namespace librapid {
10331033
/// \return Hyperbolic sine function object
10341034
template<class VAL>
10351035
requires(detail::IsArrayOp<VAL>)
1036-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sinh(VAL &&val)
1037-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sinh, VAL> {
1036+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1037+
sinh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sinh, VAL> {
10381038
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sinh>(
10391039
std::forward<VAL>(val));
10401040
}
@@ -1048,8 +1048,8 @@ namespace librapid {
10481048
/// \return Hyperbolic cosine function object
10491049
template<class VAL>
10501050
requires(detail::IsArrayOp<VAL>)
1051-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cosh(VAL &&val)
1052-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cosh, VAL> {
1051+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1052+
cosh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cosh, VAL> {
10531053
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cosh>(
10541054
std::forward<VAL>(val));
10551055
}
@@ -1063,8 +1063,8 @@ namespace librapid {
10631063
/// \return Hyperbolic tangent function object
10641064
template<class VAL>
10651065
requires(detail::IsArrayOp<VAL>)
1066-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto tanh(VAL &&val)
1067-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tanh, VAL> {
1066+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1067+
tanh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Tanh, VAL> {
10681068
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Tanh>(
10691069
std::forward<VAL>(val));
10701070
}
@@ -1078,8 +1078,8 @@ namespace librapid {
10781078
/// \return Hyperbolic sine function object
10791079
template<class VAL>
10801080
requires(detail::IsArrayOp<VAL>)
1081-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto asinh(VAL &&val)
1082-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Asinh, VAL> {
1081+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1082+
asinh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Asinh, VAL> {
10831083
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Asinh>(
10841084
std::forward<VAL>(val));
10851085
}
@@ -1093,8 +1093,8 @@ namespace librapid {
10931093
/// \return Hyperbolic cosine function object
10941094
template<class VAL>
10951095
requires(detail::IsArrayOp<VAL>)
1096-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto acosh(VAL &&val)
1097-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Acosh, VAL> {
1096+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1097+
acosh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Acosh, VAL> {
10981098
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Acosh>(
10991099
std::forward<VAL>(val));
11001100
}
@@ -1108,8 +1108,8 @@ namespace librapid {
11081108
/// \return Hyperbolic tangent function object
11091109
template<class VAL>
11101110
requires(detail::IsArrayOp<VAL>)
1111-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto atanh(VAL &&val)
1112-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Atanh, VAL> {
1111+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1112+
atanh(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Atanh, VAL> {
11131113
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Atanh>(
11141114
std::forward<VAL>(val));
11151115
}
@@ -1123,8 +1123,8 @@ namespace librapid {
11231123
/// \return Exponential function object
11241124
template<class VAL>
11251125
requires(detail::IsArrayOp<VAL>)
1126-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto exp(VAL &&val)
1127-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp, VAL> {
1126+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1127+
exp(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp, VAL> {
11281128
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Exp>(
11291129
std::forward<VAL>(val));
11301130
}
@@ -1138,8 +1138,8 @@ namespace librapid {
11381138
/// \return Exponential function object
11391139
template<class VAL>
11401140
requires(detail::IsArrayOp<VAL>)
1141-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto exp2(VAL &&val)
1142-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp2, VAL> {
1141+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1142+
exp2(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp2, VAL> {
11431143
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Exp2>(
11441144
std::forward<VAL>(val));
11451145
}
@@ -1153,8 +1153,8 @@ namespace librapid {
11531153
/// \return Exponential function object
11541154
template<class VAL>
11551155
requires(detail::IsArrayOp<VAL>)
1156-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto exp10(VAL &&val)
1157-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp10, VAL> {
1156+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1157+
exp10(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Exp10, VAL> {
11581158
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Exp10>(
11591159
std::forward<VAL>(val));
11601160
}
@@ -1168,8 +1168,8 @@ namespace librapid {
11681168
/// \return Natural logarithm function object
11691169
template<class VAL>
11701170
requires(detail::IsArrayOp<VAL>)
1171-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log(VAL &&val)
1172-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log, VAL> {
1171+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1172+
log(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log, VAL> {
11731173
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log>(
11741174
std::forward<VAL>(val));
11751175
}
@@ -1183,8 +1183,8 @@ namespace librapid {
11831183
/// \return Base 10 logarithm function object
11841184
template<class VAL>
11851185
requires(detail::IsArrayOp<VAL>)
1186-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log10(VAL &&val)
1187-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log10, VAL> {
1186+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1187+
log10(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log10, VAL> {
11881188
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log10>(
11891189
std::forward<VAL>(val));
11901190
}
@@ -1198,8 +1198,8 @@ namespace librapid {
11981198
/// \return Base 2 logarithm function object
11991199
template<class VAL>
12001200
requires(detail::IsArrayOp<VAL>)
1201-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto log2(VAL &&val)
1202-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log2, VAL> {
1201+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1202+
log2(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Log2, VAL> {
12031203
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Log2>(
12041204
std::forward<VAL>(val));
12051205
}
@@ -1213,8 +1213,8 @@ namespace librapid {
12131213
/// \return Square root function object
12141214
template<class VAL>
12151215
requires(detail::IsArrayOp<VAL>)
1216-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto sqrt(VAL &&val)
1217-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sqrt, VAL> {
1216+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1217+
sqrt(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Sqrt, VAL> {
12181218
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Sqrt>(
12191219
std::forward<VAL>(val));
12201220
}
@@ -1228,8 +1228,8 @@ namespace librapid {
12281228
/// \return Cube root function object
12291229
template<class VAL>
12301230
requires(detail::IsArrayOp<VAL>)
1231-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto cbrt(VAL &&val)
1232-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cbrt, VAL> {
1231+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1232+
cbrt(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Cbrt, VAL> {
12331233
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Cbrt>(
12341234
std::forward<VAL>(val));
12351235
}
@@ -1243,8 +1243,8 @@ namespace librapid {
12431243
/// \return Absolute value function object
12441244
template<class VAL>
12451245
requires(detail::IsArrayOp<VAL>)
1246-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto abs(VAL &&val)
1247-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Abs, VAL> {
1246+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1247+
abs(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Abs, VAL> {
12481248
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Abs>(
12491249
std::forward<VAL>(val));
12501250
}
@@ -1258,8 +1258,8 @@ namespace librapid {
12581258
/// \return Floor function object
12591259
template<class VAL>
12601260
requires(detail::IsArrayOp<VAL>)
1261-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto floor(VAL &&val)
1262-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Floor, VAL> {
1261+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1262+
floor(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Floor, VAL> {
12631263
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Floor>(
12641264
std::forward<VAL>(val));
12651265
}
@@ -1273,11 +1273,11 @@ namespace librapid {
12731273
/// \return Ceiling function object
12741274
template<class VAL>
12751275
requires(detail::IsArrayOp<VAL>)
1276-
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto ceil(VAL &&val)
1277-
-> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Ceil, VAL> {
1276+
LIBRAPID_NODISCARD LIBRAPID_ALWAYS_INLINE auto
1277+
ceil(VAL &&val) -> detail::Function<typetraits::DescriptorType_t<VAL>, detail::Ceil, VAL> {
12781278
return detail::makeFunction<typetraits::DescriptorType_t<VAL>, detail::Ceil>(
12791279
std::forward<VAL>(val));
12801280
}
12811281
} // namespace librapid
12821282

1283-
#endif // LIBRAPID_ARRAY_OPERATIONS_HPP
1283+
#endif // LIBRAPID_ARRAY_OPERATIONS_HPP

librapid/include/librapid/core/gnuConfig.hpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
#ifndef LIBRAPID_CORE_GNU_CONFIG_HPP
22
#define LIBRAPID_CORE_GNU_CONFIG_HPP
33

4-
#define LIBRAPID_INLINE inline
4+
#define LIBRAPID_INLINE inline
55

66
#if defined(LIBRAPID_NO_ALWAYS_INLINE)
77
# define LIBRAPID_ALWAYS_INLINE inline
88
#else
99
# define LIBRAPID_ALWAYS_INLINE inline __attribute__((always_inline))
1010
#endif
1111

12+
#define LIBRAPID_FLATTEN __attribute__((flatten))
13+
1214
#if defined(LIBRAPID_ENABLE_ASSERT)
1315

1416
# define LIBRAPID_ASSERT(condition, message, ...) \
@@ -43,4 +45,4 @@
4345

4446
#endif // LIBRAPID_ENABLE_ASSERT
4547

46-
#endif // LIBRAPID_CORE_GNU_CONFIG_HPP
48+
#endif // LIBRAPID_CORE_GNU_CONFIG_HPP

0 commit comments

Comments
 (0)