core: make owning pointers a top-level features

The undo-code uses owning pointers based on std::unique_ptr to
manage lifetime of C-objects. Since these are generally useful,
move them from the undo-code to the core-code. In fact, this
eliminates one instance of code duplication.

Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
Berthold Stoeger 2022-11-06 12:18:27 +01:00 committed by bstoeger
parent 5b1557ccb1
commit c5d6e0f44f
7 changed files with 50 additions and 31 deletions

View file

@ -206,6 +206,7 @@ HEADERS += \
core/extradata.h \ core/extradata.h \
core/git-access.h \ core/git-access.h \
core/globals.h \ core/globals.h \
core/owning_ptrs.h \
core/pref.h \ core/pref.h \
core/profile.h \ core/profile.h \
core/qthelper.h \ core/qthelper.h \

View file

@ -30,8 +30,8 @@ void clear(); // Reset the undo stack. Delete all commands.
void setClean(); // Call after save - this marks a state where no changes need to be saved. void setClean(); // Call after save - this marks a state where no changes need to be saved.
bool isClean(); // Any changes need to be saved? bool isClean(); // Any changes need to be saved?
QAction *undoAction(QObject *parent); // Create an undo action. QAction *undoAction(QObject *parent); // Create an undo action.
QAction *redoAction(QObject *parent); // Create an redo action. QAction *redoAction(QObject *parent); // Create a redo action.
QString changesMade(); // return a string with the texts from all commands on the undo stack -> for commit message QString changesMade(); // Return a string with the texts from all commands on the undo stack -> for commit message.
bool placingCommand(); // Currently executing a new command -> might not have to update the field the user just edited. bool placingCommand(); // Currently executing a new command -> might not have to update the field the user just edited.
// 2) Dive-list related commands // 2) Dive-list related commands

View file

@ -7,6 +7,7 @@
#include "core/divesite.h" #include "core/divesite.h"
#include "core/trip.h" #include "core/trip.h"
#include "core/dive.h" #include "core/dive.h"
#include "core/owning_ptrs.h"
#include <QUndoCommand> #include <QUndoCommand>
#include <QCoreApplication> // For Q_DECLARE_TR_FUNCTIONS #include <QCoreApplication> // For Q_DECLARE_TR_FUNCTIONS
@ -153,26 +154,6 @@ QVector<T> stdToQt(const std::vector<T> &v)
// We put everything in a namespace, so that we can shorten names without polluting the global namespace // We put everything in a namespace, so that we can shorten names without polluting the global namespace
namespace Command { namespace Command {
// Classes used to automatically call the appropriate free_*() function for owning pointers that go out of scope.
struct DiveDeleter {
void operator()(dive *d) { free_dive(d); }
};
struct TripDeleter {
void operator()(dive_trip *t) { free_trip(t); }
};
struct DiveSiteDeleter {
void operator()(dive_site *ds) { free_dive_site(ds); }
};
struct EventDeleter {
void operator()(event *ev) { free(ev); }
};
// Owning pointers to dive, dive_trip, dive_site and event objects.
typedef std::unique_ptr<dive, DiveDeleter> OwningDivePtr;
typedef std::unique_ptr<dive_trip, TripDeleter> OwningTripPtr;
typedef std::unique_ptr<dive_site, DiveSiteDeleter> OwningDiveSitePtr;
typedef std::unique_ptr<event, EventDeleter> OwningEventPtr;
// This is the base class of all commands. // This is the base class of all commands.
// It defines the Qt-translation functions // It defines the Qt-translation functions
class Base : public QUndoCommand { class Base : public QUndoCommand {

View file

@ -132,6 +132,7 @@ set(SUBSURFACE_CORE_LIB_SRCS
metrics.cpp metrics.cpp
metrics.h metrics.h
ostctools.c ostctools.c
owning_ptrs.h
parse-gpx.cpp parse-gpx.cpp
parse-xml.c parse-xml.c
parse.c parse.c

41
core/owning_ptrs.h Normal file
View file

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0
// Convenience classes defining owning pointers to C-objects that
// automatically clean up the objects if the pointers go out of
// scope. Based on unique_ptr<>.
// In the future, we should replace these by real destructors.
#ifndef OWNING_PTR_H
#define OWNING_PTR_H
#include <memory>
#include <cstdlib>
struct dive;
struct dive_trip;
struct dive_site;
struct event;
extern "C" void free_dive(struct dive *);
extern "C" void free_trip(struct dive_trip *);
extern "C" void free_dive_site(struct dive_site *);
// Classes used to automatically call the appropriate free_*() function for owning pointers that go out of scope.
struct DiveDeleter {
void operator()(dive *d) { free_dive(d); }
};
struct TripDeleter {
void operator()(dive_trip *t) { free_trip(t); }
};
struct DiveSiteDeleter {
void operator()(dive_site *ds) { free_dive_site(ds); }
};
struct EventDeleter {
void operator()(event *ev) { free(ev); }
};
// Owning pointers to dive, dive_trip, dive_site and event objects.
using OwningDivePtr = std::unique_ptr<dive, DiveDeleter>;
using OwningTripPtr = std::unique_ptr<dive_trip, TripDeleter>;
using OwningDiveSitePtr = std::unique_ptr<dive_site, DiveSiteDeleter>;
using OwningEventPtr = std::unique_ptr<event, EventDeleter>;
#endif

View file

@ -5,10 +5,10 @@
#define PROFILEWIDGET_H #define PROFILEWIDGET_H
#include "ui_profilewidget.h" #include "ui_profilewidget.h"
#include "core/owning_ptrs.h"
#include "core/subsurface-qt/divelistnotifier.h" #include "core/subsurface-qt/divelistnotifier.h"
#include <vector> #include <vector>
#include <memory>
struct dive; struct dive;
class ProfileWidget2; class ProfileWidget2;
@ -40,11 +40,6 @@ slots:
void stopRemoved(int count); void stopRemoved(int count);
void stopMoved(int count); void stopMoved(int count);
private: private:
// The same code is in command/command_base.h. Should we make that a global feature?
struct DiveDeleter {
void operator()(dive *d) { free_dive(d); }
};
std::unique_ptr<EmptyView> emptyView; std::unique_ptr<EmptyView> emptyView;
std::vector<QAction *> toolbarActions; std::vector<QAction *> toolbarActions;
Ui::ProfileWidget ui; Ui::ProfileWidget ui;
@ -53,7 +48,7 @@ private:
void editDive(); void editDive();
void exitEditMode(); void exitEditMode();
void rotateDC(int dir); void rotateDC(int dir);
std::unique_ptr<dive, DiveDeleter> editedDive; OwningDivePtr editedDive;
int editedDc; int editedDc;
dive *originalDive; dive *originalDive;
bool placingCommand; bool placingCommand;

View file

@ -897,7 +897,7 @@ void QMLManager::refreshDiveList()
// The following structure describes such a change caused by a dive edit. // The following structure describes such a change caused by a dive edit.
// Hopefully, we can remove this in due course by using finer-grained undo-commands. // Hopefully, we can remove this in due course by using finer-grained undo-commands.
struct DiveSiteChange { struct DiveSiteChange {
Command::OwningDiveSitePtr createdDs; // not-null if we created a dive site. OwningDiveSitePtr createdDs; // not-null if we created a dive site.
dive_site *editDs = nullptr; // not-null if we are supposed to edit an existing dive site. dive_site *editDs = nullptr; // not-null if we are supposed to edit an existing dive site.
location_t location = zero_location; // new value of the location if we edit an existing dive site. location_t location = zero_location; // new value of the location if we edit an existing dive site.
@ -1181,7 +1181,7 @@ void QMLManager::commitChanges(QString diveId, QString number, QString date, QSt
QStringLiteral("state :'%1'\n").arg(state); QStringLiteral("state :'%1'\n").arg(state);
} }
Command::OwningDivePtr d_ptr(alloc_dive()); // Automatically delete dive if we exit early! OwningDivePtr d_ptr(alloc_dive()); // Automatically delete dive if we exit early!
dive *d = d_ptr.get(); dive *d = d_ptr.get();
copy_dive(orig, d); copy_dive(orig, d);