Skip to content

Commit 4b845ad

Browse files
committed
phy: improve re_measurement
Make sure modular_re_measurement objects can be created from constant re_measurement ones.
1 parent 1d7a3c1 commit 4b845ad

File tree

1 file changed

+56
-14
lines changed

1 file changed

+56
-14
lines changed

include/srsran/phy/upper/re_measurement.h

Lines changed: 56 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ template <typename measure_type>
5959
class re_measurement
6060
{
6161
public:
62+
using value_type = std::remove_cv_t<measure_type>;
63+
6264
/// Default destructor
6365
virtual ~re_measurement() = default;
6466

@@ -80,12 +82,42 @@ class re_measurement
8082
};
8183

8284
/// \brief Modular resource element measurement.
85+
///
86+
/// A modular resource element is a collection of views to symbols organized in slices. All symbols must have the same
87+
/// size (number of subcarriers).
88+
///
89+
/// A \c modular_re_measurement object can be created from another \c re_measurement-based object, for instance to
90+
/// restrict access to a subset of subcarriers. The constructor preserves the const-qualification of the original object
91+
/// (e.g., a read-only \c re_measurement generates a read-only \c modular_re_measurement).
92+
///
8393
/// \tparam measure_type Underlying data type.
84-
/// \tparam MaxNofSymbols Maximum number of symbols.
94+
/// \tparam MaxNofSymbols Maximum number of symbols per slice.
8595
/// \tparam MaxNofSlices Maximum number of slices.
8696
template <typename measure_type, unsigned MaxNofSymbols, unsigned MaxNofSlices>
8797
class modular_re_measurement : public re_measurement<measure_type>
8898
{
99+
private:
100+
/// Metaprogramming for checking types in the constructors.
101+
///@{
102+
/// Default failing compatibility test.
103+
template <typename T, typename = void>
104+
struct is_modular_compatible : std::false_type {};
105+
106+
/// \brief Compatibility test for type \c T.
107+
///
108+
/// Type T can be used to construct a modular_re_measurement<measure_type> object if re_measurement is the base class
109+
/// of T and if we can create span<measure_type> from span<T::value_type>.
110+
template <typename T>
111+
struct is_modular_compatible<T, std::void_t<typename T::value_type>>
112+
: std::conditional_t<
113+
std::is_base_of_v<re_measurement<typename T::value_type>, T> &&
114+
std::is_convertible_v<
115+
std::conditional_t<std::is_const_v<T>, const typename T::value_type, typename T::value_type> (*)[],
116+
measure_type (*)[]>,
117+
std::true_type,
118+
std::false_type> {};
119+
///@}
120+
89121
public:
90122
/// Default constructor - creates an empty RE measurement object.
91123
modular_re_measurement() = default;
@@ -94,13 +126,15 @@ class modular_re_measurement : public re_measurement<measure_type>
94126
modular_re_measurement(const re_measurement_dimensions& dimensions_) { resize(dimensions_); }
95127

96128
/// Creates a modular RE measurement object from another RE measurement object.
97-
modular_re_measurement(re_measurement<measure_type>& other) : modular_re_measurement(other, 0, other.size().nof_subc)
129+
template <typename U, std::enable_if_t<is_modular_compatible<U>::value, int> = 0>
130+
modular_re_measurement(U& other) : modular_re_measurement(other, 0, other.size().nof_subc)
98131
{
99132
}
100133

101134
/// Creates a modular RE measurement object from another RE measurement object with an offset and number of
102135
/// subcarriers.
103-
modular_re_measurement(re_measurement<measure_type>& other, unsigned offset, unsigned nof_subc)
136+
template <typename U, std::enable_if_t<is_modular_compatible<U>::value, int> = 0>
137+
modular_re_measurement(U& other, unsigned offset, unsigned nof_subc)
104138
{
105139
assign(other, offset, nof_subc);
106140
}
@@ -152,8 +186,12 @@ class modular_re_measurement : public re_measurement<measure_type>
152186
std::fill_n(data.get_data().begin(), dims.nof_slices * dims.nof_symbols, span<measure_type>());
153187
}
154188

155-
/// Sets a symbol view.
156-
void set_symbol(unsigned i_symbol, unsigned i_slice, span<measure_type> view)
189+
/// \brief Sets a symbol view.
190+
///
191+
/// This method is available only if a view <t>span<U></t> is compatible with the data type of the RE measurements
192+
/// stored in the calling object.
193+
template <typename U, std::enable_if_t<std::is_convertible_v<U (*)[], measure_type (*)[]>, int> = 0>
194+
void set_symbol(unsigned i_symbol, unsigned i_slice, span<U> view)
157195
{
158196
srsran_assert(i_slice < dimensions.nof_slices,
159197
"Slice index (i.e., {}) exceeds the number of slices (i.e., {}).",
@@ -171,10 +209,15 @@ class modular_re_measurement : public re_measurement<measure_type>
171209
}
172210

173211
/// Assigns the views of the resource element measurement to another measurement.
174-
void assign(re_measurement<measure_type>& other) { assign(other, 0, other.size().nof_subc); }
212+
template <typename U, std::enable_if_t<is_modular_compatible<U>::value, int> = 0>
213+
void assign(U& other)
214+
{
215+
assign(other, 0, other.size().nof_subc);
216+
}
175217

176218
/// Assigns the views of the resource element measurement to another measurement with a subcarrier offset.
177-
void assign(re_measurement<measure_type>& other, unsigned offset, unsigned nof_subc)
219+
template <typename U, std::enable_if_t<is_modular_compatible<U>::value, int> = 0>
220+
void assign(U& other, unsigned offset, unsigned nof_subc)
178221
{
179222
const re_measurement_dimensions& base_dims = other.size();
180223
srsran_assert(offset + nof_subc <= base_dims.nof_subc, "Invalid offset and number of subcarriers.");
@@ -191,8 +234,7 @@ class modular_re_measurement : public re_measurement<measure_type>
191234
private:
192235
re_measurement_dimensions dimensions;
193236
static_tensor<2, span<measure_type>, MaxNofSymbols * MaxNofSlices> data;
194-
195-
}; // namespace srsran
237+
};
196238

197239
namespace detail {
198240

@@ -322,16 +364,16 @@ class static_re_measurement
322364
/// Constructor: checks template type.
323365
static_re_measurement()
324366
{
325-
static_assert(std::is_same<measure_type, float>::value || std::is_same<measure_type, cf_t>::value ||
326-
std::is_same<measure_type, cbf16_t>::value,
367+
static_assert(std::is_same_v<measure_type, float> || std::is_same_v<measure_type, cf_t> ||
368+
std::is_same_v<measure_type, cbf16_t>,
327369
"At the moment, this template is only available for float, cf_t and cbf16_t.");
328370
base::reserved_dims = {MAX_NOF_SUBC, MAX_NOF_SYMBOLS, MAX_NOF_SLICES};
329371
}
330372

331373
/// Constructor: sets the size of the internal buffer.
332374
explicit static_re_measurement(const re_measurement_dimensions& dims) : static_re_measurement()
333375
{
334-
static_assert(std::is_same<measure_type, float>::value || std::is_same<measure_type, cf_t>::value,
376+
static_assert(std::is_same_v<measure_type, float> || std::is_same_v<measure_type, cf_t>,
335377
"At the moment, this template is only available for float and cf_t.");
336378
base::resize(dims);
337379
}
@@ -356,7 +398,7 @@ class dynamic_re_measurement
356398
/// Constructor: checks template type and reserves internal memory.
357399
dynamic_re_measurement()
358400
{
359-
static_assert(std::is_same<measure_type, float>::value || std::is_same<measure_type, cf_t>::value,
401+
static_assert(std::is_same_v<measure_type, float> || std::is_same_v<measure_type, cf_t>,
360402
"At the moment, this template is only available for float and cf_t.");
361403
}
362404

@@ -367,7 +409,7 @@ class dynamic_re_measurement
367409
/// \warning This method entails a heap memory allocation.
368410
void reserve(const re_measurement_dimensions& dims)
369411
{
370-
static_assert(std::is_same<measure_type, float>::value || std::is_same<measure_type, cf_t>::value,
412+
static_assert(std::is_same_v<measure_type, float> || std::is_same_v<measure_type, cf_t>,
371413
"At the moment, this template is only available for float and cf_t.");
372414

373415
base::reserved_dims = dims;

0 commit comments

Comments
 (0)