27#include <unordered_map>
28#include <unordered_set>
31#include "../BaseTypes.h"
72 size_t h1 = std::hash<std::string>{}(k.partId);
73 size_t h2 = std::hash<int>{}(k.staffNo);
74 return h1 ^ (h2 + 0x9e3779b9u + (h1 << 6) + (h1 >> 2));
79using LayoutStaffKeySet = std::unordered_set<StaffKey, StaffKeyHash>;
93[[nodiscard]]
inline std::optional<LayoutStaffKeySet>
96 const auto sources = staff.sources();
97 if (sources.empty()) {
104 bool anyMissingVoice =
false;
105 std::unordered_set<std::string> voices;
108 std::unordered_map<StaffKey, KeyState, StaffKeyHash> stateByKey;
109 stateByKey.reserve(sources.size());
111 for (
const auto src : sources) {
112 const std::string partId = src.part();
113 if (partId.empty()) {
117 const StaffKey key{partId, src.staff()};
118 auto& st = stateByKey[key];
121 const auto v = src.voice();
123 st.anyMissingVoice =
true;
131 if (!st.voices.emplace(*v).second) {
137 for (
const auto& kv : stateByKey) {
138 const KeyState& st = kv.second;
140 if (st.anyMissingVoice || st.voices.size() != st.count) {
146 LayoutStaffKeySet result;
147 result.reserve(stateByKey.size());
148 for (
const auto& kv : stateByKey) {
149 result.insert(kv.first);
164[[nodiscard]]
inline std::optional<std::vector<layout::Staff>>
165flattenLayoutStaves(
const Layout& layout)
167 auto content = layout.content();
168 std::vector<layout::Staff> result;
169 result.reserve(content.size());
171 const auto walk = [&](
auto&& self,
const layout::LayoutContent& content) -> std::optional<bool> {
172 for (
auto elem : content) {
174 layout::Group g = elem.get<layout::Group>();
175 auto ok = self(self, g.content());
180 result.push_back(elem.get<layout::Staff>());
188 if (!walk(walk, content)) {
317[[nodiscard]]
inline std::optional<std::vector<LayoutSpan>>
320 const auto content = layout.content();
321 std::vector<LayoutSpan> spans;
322 spans.reserve(content.size());
324 size_t staffIndex = 0;
325 size_t encounter = 0;
327 struct SortKey {
size_t start, depth, encounter; };
334 std::vector<TaggedSpan> tagged;
335 tagged.reserve(content.size());
341 [&](
auto&& self,
const layout::LayoutContent& arr,
size_t depth)
342 -> std::optional<std::optional<std::pair<size_t,size_t>>>
344 std::optional<size_t> first;
345 std::optional<size_t> last;
347 for (
auto elem : arr) {
349 layout::Staff
s = elem.get<layout::Staff>();
351 const size_t i = staffIndex++;
355 span.depth = depth + 1;
358 span.symbol =
s.symbol();
359 span.label =
s.label();
360 span.labelref =
s.labelref();
362 span.sources = util::analyzeLayoutStaffVoices(
s);
364 tagged.push_back({ std::move(span), SortKey{i, depth + 1, encounter++} });
366 first = first.value_or(i);
369 layout::Group g = elem.get<layout::Group>();
371 auto childRange = self(self, g.content(), depth + 1);
378 const auto [cFirst, cLast] = **childRange;
383 span.startIndex = cFirst;
384 span.endIndex = cLast;
385 span.symbol = g.symbol();
386 span.label = g.label();
387 span.barlineOverride = g.calcBarlineOverride();
389 tagged.push_back({ std::move(span), SortKey{cFirst, depth, encounter++} });
391 first = first.value_or(cFirst);
398 if (!first || !last) {
399 return std::optional<std::pair<size_t,size_t>>{};
401 return std::make_pair(*first, *last);
404 auto rootRange = walk(walk, content, 0);
410 std::stable_sort(tagged.begin(), tagged.end(),
411 [](
const TaggedSpan& a,
const TaggedSpan& b)
413 if (a.key.start != b.key.start) return a.key.start < b.key.start;
414 if (a.key.depth != b.key.depth) return a.key.depth < b.key.depth;
415 return a.key.encounter < b.key.encounter;
418 spans.reserve(tagged.size());
419 for (
auto& t : tagged) spans.push_back(std::move(t.span));
440[[nodiscard]]
inline std::vector<LayoutSpan>
441buildDefaultLayoutSpans(
const Array<Part>& parts)
443 std::vector<LayoutSpan> result;
446 for (
const auto& part : parts) {
447 const size_t numStaves =
static_cast<size_t>(part.staves());
448 if (numStaves == 0) {
451 size_t staffDepth = 1;
452 bool staffNameNeeded =
true;
454 LayoutSpan groupSpan;
458 groupSpan.startIndex = staffIdx;
459 groupSpan.endIndex = staffIdx + numStaves - 1;
460 groupSpan.label = part.name();
462 staffNameNeeded =
false;
463 result.emplace_back(std::move(groupSpan));
465 for (
size_t x = 0; x < numStaves; x++) {
466 LayoutSpan staffSpan;
467 staffSpan.depth = staffDepth;
469 staffSpan.startIndex = staffIdx;
470 staffSpan.endIndex = staffIdx;
473 if (staffNameNeeded) {
474 staffSpan.label = part.name();
476 result.emplace_back(std::move(staffSpan));
Represents the element of the layout array in an MNX document.
Definition Layout.h:170
static constexpr std::string_view ContentTypeValue
type value that identifies the type within the content array
Definition Layout.h:154
Represents a single staff instance within an MNX layout.
Definition Layout.h:102
static constexpr std::string_view ContentTypeValue
type value that identifies the type within the content array
Definition Layout.h:121
StaffGroupBarlineOverride
Resolved barline override setting for a layout staff group.
Definition Enumerations.h:427
@ Unified
override with unified barline
@ s
"s-" as in sforzando (sf)
LayoutSymbol
The symbols available to bracket a staff group.
Definition Enumerations.h:245
@ NoSymbol
the default (none)
Describes a visual span in a flattened MNX layout.
Definition LayoutHelpers.h:209
LayoutSymbol symbol
Layout symbol associated with this span.
Definition LayoutHelpers.h:277
size_t startIndex
Index of the first staff covered by this span.
Definition LayoutHelpers.h:228
std::optional< LayoutStaffKeySet > sources
Optional staff sources associated with this span.
Definition LayoutHelpers.h:293
std::optional< LabelRef > labelref
Optional label reference associated with this span.
Definition LayoutHelpers.h:268
std::optional< std::string > label
Optional label text associated with this span.
Definition LayoutHelpers.h:260
size_t endIndex
Index of the last staff covered by this span.
Definition LayoutHelpers.h:237
size_t depth
Nesting depth of this span within the layout hierarchy.
Definition LayoutHelpers.h:252
StaffGroupBarlineOverride barlineOverride
Resolved barline override associated with this span.
Definition LayoutHelpers.h:285
Kind
Identifies whether this span represents a staff or a group.
Definition LayoutHelpers.h:215
@ Group
Span represents a group of staves.
@ Staff
Span represents a single staff.
Kind kind
The kind of layout element represented by this span.
Definition LayoutHelpers.h:220
Hash functor for StaffKey.
Definition LayoutHelpers.h:65
size_t operator()(const StaffKey &k) const noexcept
Computes a hash value for a StaffKey.
Definition LayoutHelpers.h:70
Identifies a specific staff within a specific part.
Definition LayoutHelpers.h:44
std::string partId
The ID of the part.
Definition LayoutHelpers.h:46
bool operator==(const StaffKey &o) const noexcept
Equality comparison.
Definition LayoutHelpers.h:55
int staffNo
The 1-based staff number within the part.
Definition LayoutHelpers.h:49