-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Respect clue list ordering from file and expand initial clue selection. #141
Conversation
Change Clues from a map, which is ordered alphabetically, to a vector, which retains insertion order. This should make no difference for regular crosswords (and there is special logic to handle Across/Down even if out of order), but retains the order from variety puzzle formats which is more likely to be the intended viewing order. Also expand the logic used to select the initial clue; previously, we only selected the first clue's first square if there was one clue list. We now do this even if there is more than one clue list. This is more likely to be reasonable now that clue list ordering is maintained from the original file. Fixes mrichards42#134
Makes sense! I'll give this a quick test this week. |
I managed to trigger a segfault -- It doesn't happen all the time, but I can hit it pretty consistently by loading a puz file from the downloader. I'm not sure why it only seems to trigger there, but it looks like it's coming from these lines in Puzzle::SetAllClues (which is only used in load_puz): Lines 185 to 186 in 133af2b
I'm pretty sure what's happening is that the second SetClueList causes the vector to reallocate, which invalidates the |
Each call to SetClueList may invalidate references returned in previous calls, since the underlying vector might get reallocated. We instead assemble the ClueList in a local variable and set it at the end once fully assembled so we don't need to worry about the returned references.
That makes sense to me - thanks for tracking this down! I don't generally use the downloader so I hadn't noticed. Calling reserve(2) feels a bit hacky to me since it's relying on an internal implementation detail of the clue list (the fact that we expose the underlying type is IMHO not ideal - thankfully we didn't rely too much on implementation details of Map outside of the Clues class, or swapping to a vector would have been even harder). I also considered calling SetClueList twice, then calling GetClueList afterwards and taking the references from there, since they'd be valid without any insertions happening in the middle, but that also felt a bit clunky to me. So what I went with was initializing the ClueLists in local variables, and then setting them at the end once fully constructed. I'm a little shaky on whether this is safe, though - I think that what happens is that the ClueList is copied when it's set, which means it's fine that the local variables go out of scope once Puzzle::SetAllClues returns. At least it isn't crashing :) But I wasn't 100% certain if this is a reasonable assumption here. I also checked for other usage of SetClueList; the only slightly questionable one I was was in load_txt.cpp, but in that case it looks like we never modify across after the reference becomes invalidated. |
Yeah, the below code is pretty rough, but since operator[] returns Lines 148 to 150 in e310d2b
Segfault fixed, and I like your solution better than mine. |
Change Clues from a map, which is ordered alphabetically, to a vector,
which retains insertion order. This should make no difference for
regular crosswords (and there is special logic to handle Across/Down
even if out of order), but retains the order from variety puzzle formats
which is more likely to be the intended viewing order.
Also expand the logic used to select the initial clue; previously, we
only selected the first clue's first square if there was one clue list.
We now do this even if there is more than one clue list. This is more
likely to be reasonable now that clue list ordering is maintained from
the original file.
Fixes #134