Archive for the ‘C++’ Category

ODB 1.2.0 released

Wednesday, March 16th, 2011

ODB 1.2.0 was released today. In case you are not familiar with ODB, it is an object-relational mapping (ORM) system for C++. It allows you to persist C++ objects to a relational database without having to deal with tables, columns, or SQL, or manually writing any of the mapping code.

This version includes a number of major new features, small improvements, and bug fixes. For an exhaustive list of changes see the official ODB 1.2.0 release announcement. In this post I am going to examine the most notable new features in more detail.

But before we move to the technical matters, I would like to make a different kind of announcement: Constantin Michael has joined the ODB development team. For this release he focused on the Boost profile, discussed next.

Boost profile

You might have noticed that the previous release added profiles as a new feature. We didn’t discuss it much then because there were no profile implementations available at that time. It was just the ODB compiler infrastructure that we were preparing for the first profile implementation. Well, the 1.2.0 release adds the first profile implementation to ODB: the Boost profile.

ODB profiles are a generic mechanism for integrating ODB with widely-used C++ frameworks and libraries. A profile provides glue code which allows us to seamlessly persist various components, such as smart pointers, containers, and value types found in these frameworks and libraries.

In this initial release the Boost profile covers the most commonly used types from the smart_ptr, unordered, and date_time Boost libraries. For example, now we can write:

#pragma db object
class employee
{
  ...
 
  boost::gregorian::date born_;
  boost::unordered_set<std::string> emails_;
  boost::shared_ptr<employer> employer_;
};

As is evident from the code fragment above, we don’t need to do anything special to use Boost types in our persistent classes. Are there any other actions that we need to perform for the above code to work?

As mentioned above, ODB profiles are a generic mechanism that can be used to integrate ODB with a type-system of any third-party library. For example, we are currently working on another profile, this time for the Qt framework. So the ODB compiler and its runtime library don’t know anything about, say, Boost or Qt. Rather, they provide general integration support. The code that is necessary to implement a profile is packaged into a separate library called a profile library. The Boost profile implementation is provided by the libodb-boost profile library.

Now, back to our question. What do we need to do to be able to write the above code in an application that uses ODB? There are three simple steps:

  1. Download and build the profile library.
  2. Specify the profile you would like to use when invoking the ODB compiler. For example:
    odb -d mysql --profile boost employee.hxx
    
  3. Link the profile library to your application.

And that’s it. That’s all we need to do. For more detailed information on ODB profiles in general refer to Chapter 11, “Profiles Introduction” in the ODB Manual. For more information on the Boost profile see Chapter 12, “Boost Profile”.

Embedded database schema

ODB now supports embedding the database schema into the generated C++ code in addition to generating the schema as a standalone SQL file. The new ODB compiler option that allows you to select between the two approaches is --schema-format. For example:

odb -d mysql --generate-schema --schema-format embedded ...

The API usage for creating the database schema from within the application looks like this:

#include <odb/schema-catalog.hxx>
 
database& db = ...
 
transaction t (db.begin ());
schema_catalog::create_schema (db);
t.commit ();

For more details refer to Section 3.3, “Database” in the ODB Manual as well as the schema/embedded example in the odb-examples package.

There are also other important features in this release, including, transparent database reconnection, recoverable exceptions (connection_lost, timeout, and deadlock), and support for the default ODB compiler options file which can be used for installation-wide customizations. Refer to the official ODB 1.2.0 release announcement for more details on these and other features.

Controlling name visibility in C++ using-directive

Monday, February 21st, 2011

Have you ever wanted to control which names become visible when your namespace is the subject of a using-directive (e.g., using namespace std;)? Maybe you have some less-commonly used names in your namespace that you don’t want to bring into the user’s namespace in order to avoid possible conflicts with other libraries?

The other day I ran into a similar problem in ODB, the C++ ORM system I am working on. We are implementing the so-called profile libraries which provide ODB persistence support for containers, smart pointers, and value types that are found in various third-party libraries and frameworks, such as C++ TR1, Boost, and Qt. We’ve decide that the most natural way to organize these profile libraries is for each profile to have a separate namespace inside the odb namespace that will correspond to the library. So the C++ TR1 support will be in odb::tr1, Boost will be in odb::boost, etc. The advantage of this schema is that the user code looks nice and logical, for example:

typedef boost::shared_ptr<employer> employer_ptr;
typedef odb::boost::shared_ptr<employee> employee_ptr;

But, as it turns out, there is a big problem with such parallel namespace hierarchies. Consider this innocent-looking code fragment:

using namespace odb;
 
typedef boost::shared_ptr<employer> employer_ptr;

The reference to the boost namespace in the second line is now ambiguous because the using-directive in the previous line brought in the boost namespace from odb.

Asking users not to use using-directives with the odb namespace is not an option since its use to bring in all the DB-related names, such as database, transaction, etc., is quite handy. In fact, we use it ourselves in all ODB examples and tests.

The next thing we looked at while searching for a solution is changing the namespace hierarchy somehow. For example, we could rename the Boost namespace inside odb (e.g., to odb::boost_profile) to avoid the ambiguity. Or, we could hide the Boost namespace with an intermediate namespace (e.g., odb::profile::boost). This way the using-directive would only bring in the intermediate namespace saving us from the ambiguity. The major problem with these solutions is inelegance; with them the user code will no longer be as succinct.

Then we started thinking about the root of this issue. The problem is not the namespace hierarchy that is somehow bad. The problem is the indiscreet C++ using-directive mechanism. Yes, it is convenient since it allows you to bring in a whole bunch of names that you need in one fell swoop. But it will also bring in a lot of names that you don’t need or never even knew existed. Usually this is harmless but in some cases these extraneous names may collide with the ones that we actually want to use. And that’s exactly what happened in ODB.

After this analysis the ideal solution became obvious: for a given namespace we need a way to control which names are subject to the using-directive. If we had such a C++ mechanism, we could have excluded the profile namespaces from this list and the ambiguity problem would have been solved (if, for some reason, someone wanted to have, say, the odb::boost namespace brought into their current namespace, they would have been able to achieve this with a namespace alias: namespace boost = odb::boost;).

As we all know there is no such mechanism in C++ and this is probably for the best (the language is complex enough as it is). Fortunately, we can get pretty close using what I call, for a lack of a better term, a “using-directive namespace”. In a nutshell, the idea is to create a nested namespace whose sole purpose is to collect a list of names that should be “exported” with a using-directive. This list is assembled with using-declarations (and namespace aliases, if you wish to include nested namespace). In ODB we called this namespace core since it contains core ODB API names that should be sufficient for most applications. Below is an outline of the odb namespace:

namespace odb
{
  class database {...};
  class transaction {...};
 
  namespace core
  {
    using odb::database;
    using odb::transaction;
  }
 
  namespace boost
  {
    // Boost profile.
  }
 
  namespace tr1
  {
    // TR1 profile.
  }
}

On the client side, we now use odb::core instead of odb in using-directives. Note also that using-declarations and qualified names can (and should) continue using the original odb namespace; odb::core is purely for using-directives:

using namespace odb::core;
 
using odb::tr1::lazy_shared_ptr;
 
typedef odb::boost::shared_ptr<employee> employee_ptr;
 
void f (database& db);

While some users may find the odb::core syntax somewhat strange, I actually like the extra assurance it implies: you are going to get the core set of names necessary for this particular functionality instead of everything that have accumulated in this namespace, maybe even the kitchen sink. We can also create several using-directive namespaces for different parts of the library. For example, the std namespace could have been partitioned like this into std::containers, std::iostream, etc.

What do you think? Anything obvious (or not so obvious) that I missed?

XSD/e 3.2.0 released

Wednesday, February 16th, 2011

XSD/e 3.2.0 was released yesterday. In case you are not familiar with XSD/e, it is a dependency-free XML Schema to C++ compiler for mobile, embedded, and light-weight C++ applications. It provides XML parsing, serialization, XML Schema validation and XML data binding while maintaining a small footprint and portability.

This version includes a number of major new features (examined in more detail next), small improvements, and bug fixes. It also adds official support, instructions, and sample configuration files for the following platforms and toolchains:

  • Android/Android NDK
  • Symbian/CSL-GCC (GCCE)
  • Integrity 178b/Green Hills MULTI C/C++

It is now also possible to build the XSD/e runtime library for iPhoneOS/iOS with the XCode project.

Enum mapping

Probably the most visible new feature is the mapping of XML Schema enumerations to C++ enum. Consider, for example, the following schema fragment:

<simpleType name="genre">
  <restriction base="string">
    <enumeration value="romance"/>
    <enumeration value="fiction"/>
    <enumeration value="horror"/>
    <enumeration value="history"/>
    <enumeration value="philosophy"/>
  </restriction>
</simpleType>

The new interface for the genre C++ class will look like this:

class genre
{
public:
  enum value_type
  {
    romance,
    fiction,
    horror,
    history,
    philosophy
  };
 
  genre ();
  genre (value_type);
 
  void value (value_type);
  operator value_type () const
  const char* string () const;
};

And we can use this class like this:

genre g (genre::fiction);
 
if (g != genre::philosophy)
  cout << g.string () << endl;

Memory allocators

You can now configure the XSD/e runtime and generated code to perform memory management using custom memory allocator functions provided by your application instead of the standard operator new/delete. The allocator example provided with the XSD/e distribution uses this feature to completely eliminate dynamic memory allocations. In particular, the resulting object model is placed into a memory block allocated on the stack. Cool, huh?

Schema evolution

Often new features that are added to the application require changes to the corresponding schemas. In mobile and embedded systems this poses a significant challenge since it is often impossible to upgrade the devices that are out in the field. As a result, it is a common requirement that devices running older versions of the software be able to cope with data that is based on the newer versions of the schema. In this release XSD/e adds support for such schema evolution using the substitution groups mechanism. Both the ignore and passthrough models for unknown content are supported.

Configurable character encoding

It is now possible to configure the character encoding used in the application with the currently supported options being UTF-8 and ISO-8859-1. Note that this encoding is not the same as the XML document encoding that is being parsed or serialized. Rather, it is the encoding that is used inside the application. When an XML document is parsed, the character data is automatically converted to the application encoding. Similarly, when an XML document is serialized, the data in the application encoding is automatically converted to the resulting document encoding.

There are also other important features in this release, including the generation of clone functions for variable-length types, improved support for XML Schema facet validation, including xs:pattern, etc. For an exhaustive list of new features see the official XSD/e 3.2.0 release announcement.