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 ContentArray& 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)) {
316[[nodiscard]]
inline std::optional<std::vector<LayoutSpan>>
319 const auto content = layout.content();
320 std::vector<LayoutSpan> spans;
321 spans.reserve(content.size());
323 size_t staffIndex = 0;
324 size_t encounter = 0;
326 struct SortKey {
size_t start, depth, encounter; };
333 std::vector<TaggedSpan> tagged;
334 tagged.reserve(content.size());
340 [&](
auto&& self,
const ContentArray& arr,
size_t depth)
341 -> std::optional<std::optional<std::pair<size_t,size_t>>>
343 std::optional<size_t> first;
344 std::optional<size_t> last;
346 for (
auto elem : arr) {
348 layout::Staff s = elem.get<layout::Staff>();
350 const size_t i = staffIndex++;
354 span.depth = depth + 1;
357 span.symbol = s.symbol();
358 span.label = s.label();
359 span.labelref = s.labelref();
361 span.sources = util::analyzeLayoutStaffVoices(s);
363 tagged.push_back({ std::move(span), SortKey{i, depth + 1, encounter++} });
365 first = first.value_or(i);
368 layout::Group g = elem.get<layout::Group>();
370 auto childRange = self(self, g.content(), depth + 1);
377 const auto [cFirst, cLast] = **childRange;
382 span.startIndex = cFirst;
383 span.endIndex = cLast;
384 span.symbol = g.symbol();
385 span.label = g.label();
386 span.barlineOverride = g.calcBarlineOverride();
388 tagged.push_back({ std::move(span), SortKey{cFirst, depth, encounter++} });
390 first = first.value_or(cFirst);
397 if (!first || !last) {
398 return std::optional<std::pair<size_t,size_t>>{};
400 return std::make_pair(*first, *last);
403 auto rootRange = walk(walk, content, 0);
409 std::stable_sort(tagged.begin(), tagged.end(),
410 [](
const TaggedSpan& a,
const TaggedSpan& b)
412 if (a.key.start != b.key.start) return a.key.start < b.key.start;
413 if (a.key.depth != b.key.depth) return a.key.depth < b.key.depth;
414 return a.key.encounter < b.key.encounter;
417 spans.reserve(tagged.size());
418 for (
auto& t : tagged) spans.push_back(std::move(t.span));
439[[nodiscard]]
inline std::vector<LayoutSpan>
440buildDefaultLayoutSpans(
const Array<Part>& parts)
442 std::vector<LayoutSpan> result;
445 for (
const auto& part : parts) {
446 const size_t numStaves =
static_cast<size_t>(part.staves());
447 if (numStaves == 0) {
450 size_t staffDepth = 1;
451 bool staffNameNeeded =
true;
453 LayoutSpan groupSpan;
457 groupSpan.startIndex = staffIdx;
458 groupSpan.endIndex = staffIdx + numStaves - 1;
459 groupSpan.label = part.name();
461 staffNameNeeded =
false;
462 result.emplace_back(std::move(groupSpan));
464 for (
size_t x = 0; x < numStaves; x++) {
465 LayoutSpan staffSpan;
466 staffSpan.depth = staffDepth;
468 staffSpan.startIndex = staffIdx;
469 staffSpan.endIndex = staffIdx;
471 if (staffNameNeeded) {
472 staffSpan.label = part.name();
474 result.emplace_back(std::move(staffSpan));
Represents the element of the layout array in an MNX document.
Definition Layout.h:145
static constexpr std::string_view ContentTypeValue
type value that identifies the type within the content array
Definition Layout.h:135
Represents a single staff instance within an MNX layout.
Definition Layout.h:83
static constexpr std::string_view ContentTypeValue
type value that identifies the type within the content array
Definition Layout.h:102
StaffGroupBarlineOverride
Resolved barline override setting for a layout staff group.
Definition Enumerations.h:284
@ Unified
override with unified barline
Describes a visual span in a flattened MNX layout.
Definition LayoutHelpers.h:209
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:292
std::optional< LabelRef > labelref
Optional label reference associated with this span.
Definition LayoutHelpers.h:268
std::optional< LayoutSymbol > symbol
Optional layout symbol associated with this span.
Definition LayoutHelpers.h:276
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:284
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