wxMaxima
Loading...
Searching...
No Matches
MaximaItemQueue.h
Go to the documentation of this file.
1// -*- mode: c++; c-file-style: "linux"; c-basic-offset: 2; indent-tabs-mode: nil -*-
2//
3// Copyright (C) 2026 Gunter Königsmann <wxMaxima@physikbuch.de>
4//
5// This program is free software; you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation; either version 2 of the License, or
8// (at your option) any later version.
9//
10// This program is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15//
16// You should have received a copy of the GNU General Public License
17// along with this program; if not, write to the Free Software
18// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19//
20// SPDX-License-Identifier: GPL-2.0+
21
46#ifndef WXM_MAXIMAITEMQUEUE_H
47#define WXM_MAXIMAITEMQUEUE_H
48
49#include <wx/string.h>
50#include <chrono>
51#include <cstddef>
52#include <deque>
53#include <functional>
54#include <mutex>
55#include <vector>
56
63{
64public:
66 struct Item {
68 int cause = 0;
70 wxString data;
71 };
72
78 explicit MaximaItemQueue(int mergeableCause,
79 std::size_t backPressureChars = DefaultBackPressureChars)
80 : m_mergeableCause(mergeableCause), m_backPressureChars(backPressureChars) {}
81
87 bool Push(std::vector<Item> &&items);
88
93 bool Take(Item &item);
94
96 bool Empty() const;
97
99 std::size_t QueuedChars() const;
100
102 bool BackPressure() const { return QueuedChars() > m_backPressureChars; }
103
105 void Clear();
106
114 static constexpr std::size_t DefaultBackPressureChars = 64 * 1024;
115
116private:
117 const int m_mergeableCause;
118 const std::size_t m_backPressureChars;
119 mutable std::mutex m_mutex;
120 std::deque<Item> m_items;
121 std::size_t m_queuedChars = 0;
123 bool m_consumerNotified = false;
124};
125
127enum class DrainResult {
129 Empty,
131 TimeUp,
133 Stopped
134};
135
147 std::chrono::milliseconds budget,
148 const std::function<bool(MaximaItemQueue::Item &)> &take,
149 const std::function<bool(const MaximaItemQueue::Item &)> &dispatch);
150
170template <class TagMap>
171std::size_t SplitIntoItems(const wxString &buffer, const TagMap &knownTags,
172 int textCause,
173 std::vector<MaximaItemQueue::Item> &items,
174 const std::function<bool()> &stopRequested = {}) {
175 const std::size_t length = buffer.length();
176 wxString text;
177 std::size_t pos = 0;
178
179 while (pos < length) {
180 if (stopRequested && stopRequested())
181 break;
182 const std::size_t tagPos = buffer.find(wxS('<'), pos);
183 if (tagPos == wxString::npos) {
184 text.append(buffer, pos, wxString::npos);
185 pos = length;
186 break;
187 }
188 if (tagPos > pos) {
189 text.append(buffer, pos, tagPos - pos);
190 pos = tagPos;
191 continue;
192 }
193
194 auto tag = knownTags.begin();
195 bool mayBeTagStart = false;
196 for (; tag != knownTags.end(); ++tag) {
197 const wxString tagStartName = wxS("<") + tag->first + wxS(">");
198 if (buffer.compare(pos, tagStartName.length(), tagStartName) == 0)
199 break;
200 // The data ends in the middle of this start tag, for example "<mat".
201 if ((length - pos < tagStartName.length()) &&
202 tagStartName.StartsWith(buffer.substr(pos)))
203 mayBeTagStart = true;
204 }
205 if ((tag == knownTags.end()) && mayBeTagStart)
206 // Decide once the rest has arrived. Taking the "<" for text here used
207 // to turn the whole tag into text: a line of raw XML in the worksheet.
208 break;
209 if (tag == knownTags.end()) {
210 // A "<" that doesn't start a known tag is just text
211 text += buffer[pos];
212 pos++;
213 continue;
214 }
215
216 const wxString tagEndName = wxS("</") + tag->first + wxS(">");
217 const std::size_t end = buffer.find(tagEndName, pos);
218 if (end == wxString::npos)
219 // Not complete yet: wait for the rest of it.
220 break;
221 if (!text.IsEmpty()) {
222 items.push_back({textCause, text});
223 text.Clear();
224 }
225 const std::size_t tagFullLength = end + tagEndName.length() - pos;
226 items.push_back({static_cast<int>(tag->second), buffer.substr(pos, tagFullLength)});
227 pos += tagFullLength;
228 if ((pos < length) && (buffer[pos] == wxS('\n')))
229 pos++;
230 }
231
232 if (!text.IsEmpty())
233 items.push_back({textCause, std::move(text)});
234 return pos;
235}
236
237#endif // WXM_MAXIMAITEMQUEUE_H
DrainResult
Why DrainForAtMost() returned.
Definition: MaximaItemQueue.h:127
@ TimeUp
The time was used up and items may be left: come back later.
@ Stopped
dispatch() asked to stop
@ Empty
Nothing left to take.
std::size_t SplitIntoItems(const wxString &buffer, const TagMap &knownTags, int textCause, std::vector< MaximaItemQueue::Item > &items, const std::function< bool()> &stopRequested={})
Splits what Maxima sent into items.
Definition: MaximaItemQueue.h:171
DrainResult DrainForAtMost(std::chrono::milliseconds budget, const std::function< bool(MaximaItemQueue::Item &)> &take, const std::function< bool(const MaximaItemQueue::Item &)> &dispatch)
Hands items to dispatch() until none is left or the time is used up.
Definition: MaximaItemQueue.cpp:79
Items Maxima sent, on their way from the socket thread to the GUI thread.
Definition: MaximaItemQueue.h:63
static constexpr std::size_t DefaultBackPressureChars
The default for how much output may wait.
Definition: MaximaItemQueue.h:114
bool Take(Item &item)
Takes the oldest item, merged with the mergeable items that follow it.
Definition: MaximaItemQueue.cpp:42
MaximaItemQueue(int mergeableCause, std::size_t backPressureChars=DefaultBackPressureChars)
Definition: MaximaItemQueue.h:78
std::size_t QueuedChars() const
The number of characters waiting.
Definition: MaximaItemQueue.cpp:68
void Clear()
Drops everything that waits.
Definition: MaximaItemQueue.cpp:73
bool Empty() const
Whether nothing is waiting.
Definition: MaximaItemQueue.cpp:63
bool BackPressure() const
Whether the socket thread should stop reading until the GUI caught up.
Definition: MaximaItemQueue.h:102
bool Push(std::vector< Item > &&items)
Appends items.
Definition: MaximaItemQueue.cpp:28
One piece of Maxima's output: what it is, and its text.
Definition: MaximaItemQueue.h:66
int cause
What kind of data this is (a Maxima::EventCause)
Definition: MaximaItemQueue.h:68
wxString data
The data itself.
Definition: MaximaItemQueue.h:70