temporal: knarly template code to consolidate and rationalize duplicated methods
This commit is contained in:
parent
7938d8de4f
commit
f61adcd738
|
@ -1615,11 +1615,19 @@ TempoMap::dump (std::ostream& ostr) const
|
|||
ostr << "------------\n\n\n";
|
||||
}
|
||||
|
||||
template<typename T, typename T1> TempoMap::Points::const_iterator
|
||||
TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp, T (Point::*method)() const, T arg, bool can_match, bool ret_iterator_after_not_at) const
|
||||
template<class const_traits_t> typename const_traits_t::iterator_type
|
||||
TempoMap::_get_tempo_and_meter (typename const_traits_t::tempo_point_type & tp,
|
||||
typename const_traits_t::meter_point_type & mp,
|
||||
typename const_traits_t::time_reference (Point::*method)() const,
|
||||
typename const_traits_t::time_type arg,
|
||||
typename const_traits_t::iterator_type begini,
|
||||
typename const_traits_t::iterator_type endi,
|
||||
typename const_traits_t::tempo_point_type tstart,
|
||||
typename const_traits_t::meter_point_type mstart,
|
||||
bool can_match, bool ret_iterator_after_not_at) const
|
||||
{
|
||||
Points::const_iterator p;
|
||||
Points::const_iterator last_used = _points.end();
|
||||
typename const_traits_t::iterator_type p;
|
||||
typename const_traits_t::iterator_type last_used = endi;
|
||||
bool tempo_done = false;
|
||||
bool meter_done = false;
|
||||
|
||||
|
@ -1630,23 +1638,25 @@ TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp,
|
|||
tp = 0;
|
||||
mp = 0;
|
||||
|
||||
/* if the starting position is the beginning of the timeline (indicated
|
||||
* by the default constructor value for T1, then we are always allowed
|
||||
* to use the tempo & meter at that position. Without this, it would be
|
||||
* necessary to special case "can_match" in the caller if the start is
|
||||
* "zero". Instead we do that here, since common cases
|
||||
* (e.g. ::get_grid()) will use can_match = false, but may pass in a
|
||||
* zero start point.
|
||||
/* If the starting position is the beginning of the timeline (indicated
|
||||
* by the default constructor value for the time_type (superclock_t,
|
||||
* Beats, BBT_Time), then we are always allowed to use the tempo &
|
||||
* meter at that position.
|
||||
*
|
||||
* Without this, it would be necessary to special case "can_match" in
|
||||
* the caller if the start is "zero". Instead we do that here, since
|
||||
* common cases (e.g. ::get_grid()) will use can_match = false, but may
|
||||
* pass in a zero start point.
|
||||
*/
|
||||
|
||||
can_match = (can_match || arg == T1());
|
||||
can_match = (can_match || arg == typename const_traits_t::time_type ());
|
||||
|
||||
for (tp = &_tempos.front(), mp = &_meters.front(), p = _points.begin(); p != _points.end(); ++p) {
|
||||
for (tp = tstart, mp = mstart, p = begini; p != endi; ++p) {
|
||||
|
||||
TempoPoint const * tpp;
|
||||
MeterPoint const * mpp;
|
||||
typename const_traits_t::tempo_point_type tpp;
|
||||
typename const_traits_t::meter_point_type mpp;
|
||||
|
||||
if (!tempo_done && (tpp = dynamic_cast<TempoPoint const *> (&(*p))) != 0) {
|
||||
if (!tempo_done && (tpp = dynamic_cast<typename const_traits_t::tempo_point_type> (&(*p))) != 0) {
|
||||
if ((can_match && (((*p).*method)() > arg)) || (!can_match && (((*p).*method)() >= arg))) {
|
||||
tempo_done = true;
|
||||
} else {
|
||||
|
@ -1655,7 +1665,7 @@ TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp,
|
|||
}
|
||||
}
|
||||
|
||||
if (!meter_done && (mpp = dynamic_cast<MeterPoint const *> (&(*p))) != 0) {
|
||||
if (!meter_done && (mpp = dynamic_cast<typename const_traits_t::meter_point_type> (&(*p))) != 0) {
|
||||
if ((can_match && (((*p).*method)() > arg)) || (!can_match && (((*p).*method)() >= arg))) {
|
||||
meter_done = true;
|
||||
} else {
|
||||
|
@ -1670,7 +1680,7 @@ TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp,
|
|||
}
|
||||
|
||||
if (!tp || !mp) {
|
||||
return _points.end();
|
||||
return endi;
|
||||
}
|
||||
|
||||
if (ret_iterator_after_not_at) {
|
||||
|
@ -1678,9 +1688,9 @@ TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp,
|
|||
p = last_used;
|
||||
|
||||
if (can_match) {
|
||||
while (((*p).*method)() <= arg && p != _points.end()) ++p;
|
||||
while (((*p).*method)() <= arg && p != endi) ++p;
|
||||
} else {
|
||||
while (((*p).*method)() < arg && p != _points.end()) ++p;
|
||||
while (((*p).*method)() < arg && p != endi) ++p;
|
||||
}
|
||||
|
||||
return p;
|
||||
|
@ -1689,82 +1699,6 @@ TempoMap::_get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp,
|
|||
return last_used;
|
||||
}
|
||||
|
||||
template<typename T, typename T1> TempoMap::Points::iterator
|
||||
TempoMap::_get_tempo_and_meter (TempoPoint *& tp, MeterPoint *& mp, T (Point::*method)() const, T arg, bool can_match, bool ret_iterator_after_not_at)
|
||||
{
|
||||
Points::iterator p;
|
||||
Points::iterator last_used = _points.end();
|
||||
bool tempo_done = false;
|
||||
bool meter_done = false;
|
||||
|
||||
assert (!_tempos.empty());
|
||||
assert (!_meters.empty());
|
||||
assert (!_points.empty());
|
||||
|
||||
tp = 0;
|
||||
mp = 0;
|
||||
|
||||
/* if the starting position is the beginning of the timeline (indicated
|
||||
* by the default constructor value for T1, then we are always allowed
|
||||
* to use the tempo & meter at that position. Without this, it would be
|
||||
* necessary to special case "can_match" in the caller if the start is
|
||||
* "zero". Instead we do that here, since common cases
|
||||
* (e.g. ::get_grid()) will use can_match = false, but may pass in a
|
||||
* zero start point.
|
||||
*/
|
||||
|
||||
can_match = (can_match || arg == T1());
|
||||
|
||||
for (tp = &_tempos.front(), mp = &_meters.front(), p = _points.begin(); p != _points.end(); ++p) {
|
||||
|
||||
TempoPoint * tpp;
|
||||
MeterPoint * mpp;
|
||||
|
||||
if (!tempo_done && (tpp = dynamic_cast<TempoPoint*> (&(*p))) != 0) {
|
||||
if ((can_match && (((*p).*method)() > arg)) || (!can_match && (((*p).*method)() >= arg))) {
|
||||
tempo_done = true;
|
||||
} else {
|
||||
tp = tpp;
|
||||
last_used = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (!meter_done && (mpp = dynamic_cast<MeterPoint*> (&(*p))) != 0) {
|
||||
if ((can_match && (((*p).*method)() > arg)) || (!can_match && (((*p).*method)() >= arg))) {
|
||||
meter_done = true;
|
||||
} else {
|
||||
mp = mpp;
|
||||
last_used = p;
|
||||
}
|
||||
}
|
||||
|
||||
if (meter_done && tempo_done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (!tp || !mp) {
|
||||
return _points.end();
|
||||
}
|
||||
|
||||
if (ret_iterator_after_not_at) {
|
||||
|
||||
p = last_used;
|
||||
|
||||
if (can_match) {
|
||||
while (((*p).*method)() <= arg && p != _points.end()) ++p;
|
||||
} else {
|
||||
while (((*p).*method)() < arg && p != _points.end()) ++p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
return last_used;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TempoMap::get_grid (TempoMapPoints& ret, superclock_t start, superclock_t end, uint32_t bar_mod)
|
||||
{
|
||||
|
|
|
@ -862,29 +862,107 @@ class LIBTEMPORAL_API TempoMap : public PBD::StatefulDestructible
|
|||
BBT_Time bbt_at (Beats const &) const;
|
||||
BBT_Time bbt_at (superclock_t sc) const;
|
||||
|
||||
/* fetch const tempo/meter pairs */
|
||||
template<typename T, typename T1> struct const_traits {
|
||||
typedef Points::const_iterator iterator_type;
|
||||
typedef TempoPoint const * tempo_point_type;
|
||||
typedef MeterPoint const * meter_point_type;
|
||||
using time_reference = T;
|
||||
using time_type = T1;
|
||||
};
|
||||
|
||||
template<typename T, typename T1> Points::const_iterator _get_tempo_and_meter (TempoPoint const *& tp, MeterPoint const *& mp, T (Point::*method)() const, T arg, bool can_match, bool ret_iterator_after_not_at) const;
|
||||
template<typename T, typename T1> struct non_const_traits {
|
||||
typedef Points::iterator iterator_type;
|
||||
typedef TempoPoint * tempo_point_type;
|
||||
typedef MeterPoint * meter_point_type;
|
||||
using time_reference = T;
|
||||
using time_type = T1;
|
||||
};
|
||||
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, BBT_Time const & bbt, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
return _get_tempo_and_meter<BBT_Time const &, BBT_Time> (t, m, &Point::bbt, bbt, can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
return _get_tempo_and_meter<superclock_t,superclock_t> (t, m, &Point::sclock, sc, can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, Beats const & b, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
return _get_tempo_and_meter<Beats const &, Beats> (t, m, &Point::beats, b, can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
|
||||
/* fetch non-const tempo/meter pairs. As of March 2020, we only need
|
||||
* the superclock variant, but leave the templated design in place,
|
||||
* just in case.
|
||||
/* A somewhat complex method that sets a TempoPoint* and MeterPoint* to
|
||||
* refer to the correct tempo and meter points for the given start
|
||||
* time.
|
||||
*
|
||||
* It also returns an iterator which may point at the latter of the two
|
||||
* points (tempo & meter; always the meter point if they are at the
|
||||
* same time) OR may point at the iterator *after* the latter of the
|
||||
* two, depending on whether or not @param ret_iterator_after_not_at is
|
||||
* true or false.
|
||||
*
|
||||
* If @param can_match is true, the points used can be located at the
|
||||
* given time. If false, they must be before it. Setting it to false is
|
||||
* useful when you need to know the TempoMetric in effect at a given
|
||||
* time if there was no tempo or meter point at that time.
|
||||
*
|
||||
* The templated structure here is to avoid code duplication in 2
|
||||
* separate versions of this method, one that would be const, and one
|
||||
* that would be non-const. This is a challenging problem in C++, and
|
||||
* seems best solved by using a "traits" object as shown here.
|
||||
*
|
||||
* The begini, endi, tstart and mstart arguments are an additional
|
||||
* complication. If we try to use e.g. _points.begin() inside the
|
||||
* method, which is labelled const, we will always get the const
|
||||
* version of the iterator. This const iterator type will conflict with
|
||||
* the non-const iterator type defined by the "non_const_traits"
|
||||
* type. The same happens with _tempos.front() etc. This problem is
|
||||
* addressed by calling these methods in the caller method, which maybe
|
||||
* const or non-const, and will provide appropriate versions based on that.
|
||||
*/
|
||||
|
||||
template<typename T, typename T1> Points::iterator _get_tempo_and_meter (TempoPoint *& tp, MeterPoint *& mp, T (Point::*method)() const, T arg, bool can_match, bool ret_iterator_after_not_at);
|
||||
template<class constness_traits_t> typename constness_traits_t::iterator_type
|
||||
_get_tempo_and_meter (typename constness_traits_t::tempo_point_type &,
|
||||
typename constness_traits_t::meter_point_type &,
|
||||
typename constness_traits_t::time_reference (Point::*)() const,
|
||||
typename constness_traits_t::time_type,
|
||||
typename constness_traits_t::iterator_type begini,
|
||||
typename constness_traits_t::iterator_type endi,
|
||||
typename constness_traits_t::tempo_point_type tstart,
|
||||
typename constness_traits_t::meter_point_type mstart,
|
||||
bool can_match,
|
||||
bool ret_iterator_after_not_at) const;
|
||||
|
||||
/* fetch non-const tempo/meter pairs and iterator (used in
|
||||
* ::reset_starting_at() in which we will modify points.
|
||||
*/
|
||||
|
||||
Points::iterator get_tempo_and_meter (TempoPoint *& t, MeterPoint *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) {
|
||||
return _get_tempo_and_meter<superclock_t,superclock_t> (t, m, &Point::sclock, sc, can_match, ret_iterator_after_not_at);
|
||||
|
||||
/* because @param this is non-const (because the method is not
|
||||
* marked const), the following:
|
||||
|
||||
_points.begin()
|
||||
_points.end()
|
||||
_tempos.front()
|
||||
_meters.front()
|
||||
|
||||
will all be the non-const versions of these methods.
|
||||
*/
|
||||
|
||||
return _get_tempo_and_meter<non_const_traits<superclock_t,superclock_t> > (t, m, &Point::sclock, sc, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
|
||||
/* fetch const tempo/meter pairs and iterator (used in metric_at() and
|
||||
* other similar call sites where we do not modify the map
|
||||
*/
|
||||
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, BBT_Time const & bbt, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
|
||||
/* because @param this is const (because the method is marked
|
||||
* const), the following:
|
||||
|
||||
_points.begin()
|
||||
_points.end()
|
||||
_tempos.front()
|
||||
_meters.front()
|
||||
|
||||
will all be the const versions of these methods.
|
||||
*/
|
||||
return _get_tempo_and_meter<const_traits<BBT_Time const &, BBT_Time> > (t, m, &Point::bbt, bbt, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, superclock_t sc, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
return _get_tempo_and_meter<const_traits<superclock_t,superclock_t> > (t, m, &Point::sclock, sc, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
Points::const_iterator get_tempo_and_meter (TempoPoint const *& t, MeterPoint const *& m, Beats const & b, bool can_match, bool ret_iterator_after_not_at) const {
|
||||
return _get_tempo_and_meter<const_traits<Beats const &, Beats> > (t, m, &Point::beats, b, _points.begin(), _points.end(), &_tempos.front(), &_meters.front(), can_match, ret_iterator_after_not_at);
|
||||
}
|
||||
|
||||
/* parsing legacy tempo maps */
|
||||
|
|
Loading…
Reference in New Issue
Block a user