WebKit and C++11
I am happy to announce that as of r155146, we now require our various ports to build with compilers that support some C++11 features. This means that we don’t need to use the COMPILER_SUPPORTS()
macro to conditionally use these features anymore. These are:
- Type inference
- Static assertions
- Move semantics
We’ve chosen these three features because they are well-supported in recent versions of the compilers we use: clang, MSVC and GCC.
What does this mean for people writing code? Here are three code examples where these three features come in handy:
Type Inference
Type inference using the auto
keyword will automatically deduce the type of a variable based on its initializer. This is especially useful iterators. This loop:
HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator end = m_counters.end();
for (HashMap<OriginStack, OwnPtr<ExecutionCounter> >::const_iterator iter = m_counters.begin(); iter != end; ++iter) {
...
}
Becomes:
for (auto it = m_counters.begin(), end = m_counters.end(); it != end; ++it) {
...
}
Unfortunately, the new range-based for syntax is not supported by all compilers, but this is definitely a step in the right direction.
Static Assertions
The new static_assert
is a way to declare compile-time assertions. If an assertion is false
, the compiler will produce an error. WTF already has a COMPILE_ASSERT
macro that provides this functionality, but static_assert
produces better error messages.
COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
Gives the error:
/Source/WTF/wtf/text/AtomicString.cpp:43:1: error: 'dummyatomic_string_and_string_must_be_same_size' declared as an array with a negative size
COMPILE_ASSERT(sizeof(AtomicString) == sizeof(String), atomic_string_and_string_must_be_same_size);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from /Source/WTF/wtf/text/AtomicString.cpp:23:
In file included from /Source/WTF/config.h:62:
In file included from /Source/WTF/wtf/FastMalloc.h:25:
In file included from /Source/WTF/wtf/PossiblyNull.h:29:
/Source/WTF/wtf/Assertions.h:324:60: note: expanded from macro 'COMPILE_ASSERT'
#define COMPILE_ASSERT(exp, name) typedef int dummy##name [(exp) ? 1 : -1]
Whereas:
static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must have the same size");
Gives:
/Source/WTF/wtf/text/AtomicString.cpp:43:1: error: static_assert failed "AtomicString and String must have the same size"
static_assert(sizeof(AtomicString) == sizeof(String), "AtomicString and String must have the same size");
^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Move Semantics
Move semantics can provide improved performance when passing objects by value by moving the data instead of copying it. What it means for WebKit is that we can stop using out parameters in functions that return Vector
. For example:
void HTMLFormElement::getNamedElements(const AtomicString& name, Vector<RefPtr<Node> >& namedItems)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
elements()->namedItems(name, namedItems);
HTMLElement* elementFromPast = elementFromPastNamesMap(name);
if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
addToPastNamesMap(toHTMLElement(namedItems.first().get())->asFormNamedItem(), name);
else if (elementFromPast && namedItems.isEmpty())
namedItems.append(elementFromPast);
}
Becomes:
Vector<RefPtr<Node>> HTMLFormElement::namedElements(const AtomicString& name)
{
// http://www.whatwg.org/specs/web-apps/current-work/multipage/forms.html#dom-form-nameditem
Vector<RefPtr<Node>> namedItems = elements()->namedItems(name);
HTMLElement* elementFromPast = elementFromPastNamesMap(name);
if (namedItems.size() == 1 && namedItems.first() != elementFromPast)
addToPastNamesMap(toHTMLElement(namedItems.first().get())->asFormNamedItem(), name);
else if (elementFromPast && namedItems.isEmpty())
namedItems.append(elementFromPast);
return namedItems;
}
Vector
objects with a zero inline capacity as well as HashMap
and HashSet
too!Move semantics is an interesting topic that I hope to cover further in another blog post, so I’ll only mention it briefly here.
One More Thing
Astute readers may have noticed another C++11 feature in the previous example that we can now use. With C++11 there is no need to use a space between right angle brackets when closing template arguments lists! This means that:
OwnPtr<Vector<RefPtr<Node> > > m_childNodes;
Becomes:
OwnPtr<Vector<RefPtr<Node>>> m_childNodes;
Personally I’m really excited about using these features and I think they will be useful throughout the codebase. In time we’re going to start requiring even more C++11 features but this is a good start.