Skip to content

Commit

Permalink
Refactor|libcore: Convenient native access to a Record
Browse files Browse the repository at this point in the history
Added RecordAccessor as a utility that provides various get*()
methods to query values from a Record. RecordAccess is now used in
Config and Record itself.

Also added an Value::asInt() conversion method with automatic
rounding to the nearest integer, and ArrayValue indexing with native
integers as indices.
  • Loading branch information
skyjake committed May 30, 2014
1 parent ba6eadf commit eb77a29
Show file tree
Hide file tree
Showing 13 changed files with 247 additions and 200 deletions.
3 changes: 3 additions & 0 deletions doomsday/libcore/data.pri
Expand Up @@ -38,6 +38,7 @@ publicHeaders(root, \
include/de/Property \
include/de/Reader \
include/de/Record \
include/de/RecordAccessor \
include/de/RecordValue \
include/de/Refuge \
include/de/RefValue \
Expand Down Expand Up @@ -93,6 +94,7 @@ publicHeaders(data, \
include/de/data/property.h \
include/de/data/reader.h \
include/de/data/record.h \
include/de/data/recordaccessor.h \
include/de/data/recordvalue.h \
include/de/data/refuge.h \
include/de/data/refvalue.h \
Expand Down Expand Up @@ -139,6 +141,7 @@ SOURCES += \
src/data/pathtreenode.cpp \
src/data/reader.cpp \
src/data/record.cpp \
src/data/recordaccessor.cpp \
src/data/recordvalue.cpp \
src/data/refuge.cpp \
src/data/refvalue.cpp \
Expand Down
1 change: 1 addition & 0 deletions doomsday/libcore/include/de/RecordAccessor
@@ -0,0 +1 @@
#include "data/recordaccessor.h"
40 changes: 2 additions & 38 deletions doomsday/libcore/include/de/core/config.h
Expand Up @@ -24,6 +24,7 @@
#include "../String"
#include "../Path"
#include "../Version"
#include "../Record"

namespace de {

Expand All @@ -47,7 +48,7 @@ class ArrayValue;
*
* @ingroup core
*/
class DENG2_PUBLIC Config
class DENG2_PUBLIC Config : public RecordAccessor
{
public:
/**
Expand All @@ -63,43 +64,6 @@ class DENG2_PUBLIC Config
/// Writes the configuration to /home.
void write() const;

/// Returns the value of @a name as a Value.
Value const &get(String const &name) const;

/// Returns the value of @a name as an integer.
dint geti(String const &name) const;

dint geti(String const &name, dint defaultValue) const;

/// Returns the value of @a name as a boolean.
bool getb(String const &name) const;

bool getb(String const &name, bool defaultValue) const;

/// Returns the value of @a name as an unsigned integer.
duint getui(String const &name) const;

duint getui(String const &name, duint defaultValue) const;

/// Returns the value of @a name as a double-precision floating point number.
ddouble getd(String const &name) const;

ddouble getd(String const &name, ddouble defaultValue) const;

/// Returns the value of @a name as a string.
String gets(String const &name) const;

String gets(String const &name, String const &defaultValue) const;

/// Returns the value of @a name as an array value. An exception is thrown
/// if the variable does not have an array value.
ArrayValue const &geta(String const &name) const;

template <typename ValueType>
ValueType const &getAs(String const &name) const {
return names().getAs<ValueType>(name);
}

/**
* Sets the value of a variable, creating the variable if needed.
*
Expand Down
3 changes: 3 additions & 0 deletions doomsday/libcore/include/de/data/arrayvalue.h
Expand Up @@ -185,6 +185,9 @@ class DENG2_PUBLIC ArrayValue : public Value
*/
void setElement(dint index, Number value);

Value const &element(dint index) const;
Value const &operator [] (dint index) const;

private:
Elements::iterator indexToIterator(dint index);
Elements::const_iterator indexToIterator(dint index) const;
Expand Down
36 changes: 6 additions & 30 deletions doomsday/libcore/include/de/data/record.h
Expand Up @@ -26,6 +26,7 @@
#include "../Value"
#include "../Audience"
#include "../Log"
#include "../RecordAccessor"

#include <QMap>
#include <QList>
Expand All @@ -48,8 +49,11 @@ class NativeFunctionSpec;
*
* @ingroup data
*/
class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base,
DENG2_OBSERVES(Variable, Deletion)
class DENG2_PUBLIC Record
: public RecordAccessor
, public ISerializable
, public LogEntry::Arg::Base
, DENG2_OBSERVES(Variable, Deletion)
{
public:
/// Unknown variable name was given. @ingroup errors
Expand All @@ -58,9 +62,6 @@ class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base,
/// All variables and subrecords in the record must have a name. @ingroup errors
DENG2_ERROR(UnnamedError);

/// Attempted to get the value of a variable while expecting the wrong type. @ingroup errors
DENG2_ERROR(ValueTypeError);

typedef QMap<String, Variable *> Members;
typedef QMap<String, Record *> Subrecords;
typedef std::pair<String, String> KeyValue;
Expand Down Expand Up @@ -268,31 +269,6 @@ class DENG2_PUBLIC Record : public ISerializable, public LogEntry::Arg::Base,
*/
Record *remove(String const &name);

// Convenient value getters:
Value const &get(String const &name) const;
dint geti(String const &name) const;
dint geti(String const &name, dint defaultValue) const;
bool getb(String const &name) const;
bool getb(String const &name, bool defaultValue) const;
duint getui(String const &name) const;
duint getui(String const &name, duint defaultValue) const;
ddouble getd(String const &name) const;
ddouble getd(String const &name, ddouble defaultValue) const;
String gets(String const &name) const;
String gets(String const &name, String const &defaultValue) const;
ArrayValue const &geta(String const &name) const;

template <typename ValueType>
ValueType const &getAs(String const &name) const {
ValueType const *v = get(name).maybeAs<ValueType>();
if(!v)
{
throw ValueTypeError("Record::getAs", String("Cannot cast to expected type (") +
DENG2_TYPE_NAME(ValueType) + ")");
}
return *v;
}

/**
* Sets the value of a variable, creating the variable if needed.
*
Expand Down
86 changes: 86 additions & 0 deletions doomsday/libcore/include/de/data/recordaccessor.h
@@ -0,0 +1,86 @@
/** @file recordaccessor.h Utility class with get*() methods.
*
* @authors Copyright (c) 2014 Jaakko Keränen <jaakko.keranen@iki.fi>
*
* @par License
* LGPL: http://www.gnu.org/licenses/lgpl.html
*
* <small>This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 3 of the License, or (at your
* option) any later version. This program is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser
* General Public License for more details. You should have received a copy of
* the GNU Lesser General Public License along with this program; if not, see:
* http://www.gnu.org/licenses</small>
*/

#ifndef LIBDENG2_RECORDACCESSOR_H
#define LIBDENG2_RECORDACCESSOR_H

#include "../ArrayValue"

namespace de {

class Record;

/**
* Utility class with convenient get*() methods. While Record is designed to be used
* primarily by Doomsday Script, RecordAccessor makes it easy for native code to access
* the values stored in a Record, too.
*
* Record is derived from RecordAccessor, which makes these methods available in all
* Record instances, too.
*
* @ingroup data
*/
class DENG2_PUBLIC RecordAccessor
{
public:
/// Attempted to get the value of a variable while expecting the wrong type.
/// @ingroup errors
DENG2_ERROR(ValueTypeError);

public:
RecordAccessor(Record const *rec);
RecordAccessor(Record const &rec);

Record const &accessedRecord() const;

Value const &get(String const &name) const;
dint geti(String const &name) const;
dint geti(String const &name, dint defaultValue) const;
bool getb(String const &name) const;
bool getb(String const &name, bool defaultValue) const;
duint getui(String const &name) const;
duint getui(String const &name, duint defaultValue) const;
dfloat getf(String const &name) const;
dfloat getf(String const &name, dfloat defaultValue) const;
ddouble getd(String const &name) const;
ddouble getd(String const &name, ddouble defaultValue) const;
String gets(String const &name) const;
String gets(String const &name, String const &defaultValue) const;
ArrayValue const &geta(String const &name) const;

template <typename ValueType>
ValueType const &getAs(String const &name) const {
ValueType const *v = get(name).maybeAs<ValueType>();
if(!v)
{
throw ValueTypeError("RecordAccessor::getAs", String("Cannot cast to expected type (") +
DENG2_TYPE_NAME(ValueType) + ")");
}
return *v;
}

protected:
void setAccessedRecord(Record const &rec);

private:
Record const *_rec;
};

} // namespace de

#endif // LIBDENG2_RECORDACCESSOR_H
5 changes: 5 additions & 0 deletions doomsday/libcore/include/de/data/value.h
Expand Up @@ -80,6 +80,11 @@ class DENG2_PUBLIC Value : public String::IPatternArg, public ISerializable
*/
virtual Number asSafeNumber(Number const &defaultValue = 0.0) const;

/**
* Convert the value to the nearest integer. Uses asNumber().
*/
int asInt() const;

/**
* Convert the value to into a text string. All values have
* to implement this.
Expand Down
66 changes: 4 additions & 62 deletions doomsday/libcore/src/core/config.cpp
Expand Up @@ -67,8 +67,10 @@ DENG2_PIMPL_NOREF(Config)
}
};

Config::Config(Path const &path) : d(new Instance(path))
{}
Config::Config(Path const &path) : RecordAccessor(0), d(new Instance(path))
{
setAccessedRecord(names());
}

void Config::read()
{
Expand Down Expand Up @@ -186,66 +188,6 @@ Version Config::upgradedFromVersion() const
return d->oldVersion;
}

Value const &Config::get(String const &name) const
{
return names().get(name);
}

dint Config::geti(String const &name) const
{
return names().geti(name);
}

dint Config::geti(String const &name, dint defaultValue) const
{
return names().geti(name, defaultValue);
}

bool Config::getb(String const &name) const
{
return names().getb(name);
}

bool Config::getb(String const &name, bool defaultValue) const
{
return names().getb(name, defaultValue);
}

duint Config::getui(String const &name) const
{
return names().getui(name);
}

duint Config::getui(String const &name, duint defaultValue) const
{
return names().getui(name, defaultValue);
}

ddouble Config::getd(String const &name) const
{
return names().getd(name);
}

ddouble Config::getd(String const &name, ddouble defaultValue) const
{
return names().getd(name, defaultValue);
}

String Config::gets(String const &name) const
{
return names().gets(name);
}

String Config::gets(String const &name, String const &defaultValue) const
{
return names().gets(name, defaultValue);
}

ArrayValue const &Config::geta(String const &name) const
{
return names().getAs<ArrayValue>(name);
}

Variable &Config::set(String const &name, bool value)
{
return names().set(name, value);
Expand Down
10 changes: 10 additions & 0 deletions doomsday/libcore/src/data/arrayvalue.cpp
Expand Up @@ -340,3 +340,13 @@ void ArrayValue::setElement(dint index, Number value)
{
setElement(NumberValue(index), new NumberValue(value));
}

Value const &ArrayValue::element(dint index) const
{
return element(NumberValue(index));
}

Value const &ArrayValue::operator [] (dint index) const
{
return element(index);
}

0 comments on commit eb77a29

Please sign in to comment.