Skip to content

Commit

Permalink
libdeng2: Utility for the pimpl idiom
Browse files Browse the repository at this point in the history
The DENG2_PIMPL macro makes it somewhat easier to define a private
implementation struct that contains a reference to the public instance.
  • Loading branch information
skyjake committed Feb 7, 2013
1 parent 3972ce0 commit 3534776
Show file tree
Hide file tree
Showing 8 changed files with 59 additions and 41 deletions.
34 changes: 33 additions & 1 deletion doomsday/libdeng2/include/de/libdeng2.h
Expand Up @@ -205,9 +205,35 @@
#define DENG2_FOR_EACH_CONST_REVERSE(IterClass, Var, ContainerRef) \
for(IterClass::const_reverse_iterator Var = (ContainerRef).rbegin(); Var != (ContainerRef).rend(); ++Var)

#if defined(__cplusplus) && !defined(DENG2_C_API_ONLY)
/**
* Macro for starting the definition of a private implementation struct. Example:
* <pre>
* DENG2_PIMPL(MyClass)
* {
* Instance(Public &inst) : Private(inst) {
* // constructor
* }
* // private data and methods
* };
* </pre>
*/
#define DENG2_PIMPL(ClassName) \
typedef ClassName Public; \
struct ClassName::Instance : public de::Private<ClassName>

#if defined __cplusplus
namespace de {

/**
* Utility template for defining private implementation data (pimpl idiom). Use
* this in source files, not in headers.
*/
template <typename Type>
struct Private {
Type &self;
Private(Type &i) : self(i) {}
};

template <typename FromType, typename ToType>
inline ToType function_cast(FromType ptr)
{
Expand All @@ -223,6 +249,12 @@ inline ToType function_cast(FromType ptr)
return forcedCast.target;
}

} // namespace de
#endif // __cplusplus

#if defined __cplusplus && !defined DENG2_C_API_ONLY
namespace de {

/**
* All serialization in all contexts use a common protocol version number.
* Whenever anything changes in serialization, the protocol version needs to be
Expand Down
16 changes: 7 additions & 9 deletions doomsday/libdeng2/src/core/app.cpp
Expand Up @@ -41,10 +41,8 @@ namespace de {

static App *singletonApp;

struct App::Instance : DENG2_OBSERVES(Record, Deletion)
DENG2_PIMPL(App), DENG2_OBSERVES(Record, Deletion)
{
App &app;

CommandLine cmdLine;

LogBuffer logBuffer;
Expand Down Expand Up @@ -83,8 +81,8 @@ struct App::Instance : DENG2_OBSERVES(Record, Deletion)

void (*terminateFunc)(char const *);

Instance(App &a, QStringList args)
: app(a), cmdLine(args), persistentData(0), config(0), terminateFunc(0)
Instance(Public &a, QStringList args)
: Private(a), cmdLine(args), persistentData(0), config(0), terminateFunc(0)
{
singletonApp = &a;

Expand Down Expand Up @@ -126,10 +124,10 @@ struct App::Instance : DENG2_OBSERVES(Record, Deletion)
binFolder.attach(new DirectoryFeed(appDir));
if(allowPlugins)
{
binFolder.attach(new DirectoryFeed(app.nativePluginBinaryPath()));
binFolder.attach(new DirectoryFeed(self.nativePluginBinaryPath()));
}
fs.makeFolder("/data").attach(new DirectoryFeed(app.nativeBasePath()));
fs.makeFolder("/modules").attach(new DirectoryFeed(app.nativeBasePath() / "modules"));
fs.makeFolder("/data").attach(new DirectoryFeed(self.nativeBasePath()));
fs.makeFolder("/modules").attach(new DirectoryFeed(self.nativeBasePath() / "modules"));

#elif WIN32
if(allowPlugins)
Expand All @@ -150,7 +148,7 @@ struct App::Instance : DENG2_OBSERVES(Record, Deletion)
#endif

// User's home folder.
fs.makeFolder("/home").attach(new DirectoryFeed(app.nativeHomePath(),
fs.makeFolder("/home").attach(new DirectoryFeed(self.nativeHomePath(),
DirectoryFeed::AllowWrite | DirectoryFeed::CreateIfMissing));

// Populate the file system.
Expand Down
18 changes: 6 additions & 12 deletions doomsday/libdeng2/src/core/commandline.cpp
Expand Up @@ -43,7 +43,7 @@ static char *duplicateStringAsUtf8(QString const &s)
return copy;
}

struct CommandLine::Instance
DENG2_PIMPL(CommandLine)
{
QDir initialDir;

Expand All @@ -57,7 +57,7 @@ struct CommandLine::Instance
typedef std::map<std::string, ArgumentStrings> Aliases;
Aliases aliases;

Instance()
Instance(Public &i) : Private(i)
{
initialDir = QDir::current();
}
Expand Down Expand Up @@ -122,15 +122,11 @@ struct CommandLine::Instance
}
};

CommandLine::CommandLine()
{
d = new Instance;
}
CommandLine::CommandLine() : d(new Instance(*this))
{}

CommandLine::CommandLine(QStringList const &args)
CommandLine::CommandLine(QStringList const &args) : d(new Instance(*this))
{
d = new Instance;

for(int i = 0; i < args.size(); ++i)
{
if(args.at(i)[0] == '@')
Expand All @@ -145,10 +141,8 @@ CommandLine::CommandLine(QStringList const &args)
}
}

CommandLine::CommandLine(CommandLine const &other)
CommandLine::CommandLine(CommandLine const &other) : d(new Instance(*this))
{
d = new Instance;

DENG2_FOR_EACH_CONST(Instance::Arguments, i, other.d->arguments)
{
d->appendArg(*i);
Expand Down
5 changes: 2 additions & 3 deletions doomsday/libshell/src/choicewidget.cpp
Expand Up @@ -23,15 +23,14 @@
namespace de {
namespace shell {

struct ChoiceWidget::Instance
DENG2_PIMPL(ChoiceWidget)
{
ChoiceWidget &self;
Items items;
int selection;
MenuWidget *menu;
String prompt;

Instance(ChoiceWidget &inst) : self(inst), selection(0)
Instance(Public &i) : Private(i), selection(0)
{}

void updateMenu()
Expand Down
6 changes: 2 additions & 4 deletions doomsday/libshell/src/commandlinewidget.cpp
Expand Up @@ -24,10 +24,8 @@
namespace de {
namespace shell {

struct CommandLineWidget::Instance
DENG2_PIMPL(CommandLineWidget)
{
CommandLineWidget &self;

/**
* Line of text with a cursor.
*/
Expand All @@ -44,7 +42,7 @@ struct CommandLineWidget::Instance
QList<Command> history;
int historyPos;

Instance(CommandLineWidget &cli) : self(cli), historyPos(0)
Instance(Public &i) : Private(i), historyPos(0)
{
history.append(Command());
}
Expand Down
7 changes: 3 additions & 4 deletions doomsday/libshell/src/lineeditwidget.cpp
Expand Up @@ -28,9 +28,8 @@
namespace de {
namespace shell {

struct LineEditWidget::Instance
DENG2_PIMPL(LineEditWidget)
{
LineEditWidget &self;
ConstantRule *height;
bool signalOnEnter;
String prompt;
Expand All @@ -56,8 +55,8 @@ struct LineEditWidget::Instance
// Word wrapping.
LineWrapping wraps;

Instance(LineEditWidget &cli)
: self(cli),
Instance(Public &i)
: Private(i),
signalOnEnter(true),
cursor(0)
{
Expand Down
7 changes: 3 additions & 4 deletions doomsday/libshell/src/link.cpp
Expand Up @@ -27,9 +27,8 @@
namespace de {
namespace shell {

struct Link::Instance
DENG2_PIMPL(Link)
{
Link &self;
String tryingToConnectToHost;
Time startedTryingAt;
TimeDelta timeout;
Expand All @@ -39,8 +38,8 @@ struct Link::Instance
Status status;
Time connectedAt;

Instance(Link &i)
: self(i),
Instance(Public &i)
: Private(i),
socket(0),
status(Disconnected),
connectedAt(Time::invalidTime()) {}
Expand Down
7 changes: 3 additions & 4 deletions doomsday/libshell/src/menuwidget.cpp
Expand Up @@ -24,9 +24,8 @@
namespace de {
namespace shell {

struct MenuWidget::Instance
DENG2_PIMPL(MenuWidget)
{
MenuWidget &self;
ConstantRule *width;
ConstantRule *height;
TextCanvas::Char::Attribs borderAttr;
Expand All @@ -50,8 +49,8 @@ struct MenuWidget::Instance
QList<Item> items;
int cursor;

Instance(MenuWidget &inst)
: self(inst),
Instance(Public &i)
: Private(i),
borderAttr(TextCanvas::Char::Reverse),
backgroundAttr(TextCanvas::Char::Reverse),
borderStyle(LineBorder),
Expand Down

0 comments on commit 3534776

Please sign in to comment.