Paul J. Lucas has proposed merging lp:~zorba-coders/zorba/feature-mem_size into 
lp:zorba.

Requested reviews:
  Paul J. Lucas (paul-lucas)

For more details, see:
https://code.launchpad.net/~zorba-coders/zorba/feature-mem_size/+merge/114764

Added framework for calculating the total memory used by a data structure and 
using it with store::Item.
-- 
https://code.launchpad.net/~zorba-coders/zorba/feature-mem_size/+merge/114764
Your team Zorba Coders is subscribed to branch lp:zorba.
=== modified file 'src/store/api/item.h'
--- src/store/api/item.h	2012-07-12 17:29:55 +0000
+++ src/store/api/item.h	2012-07-13 00:33:23 +0000
@@ -104,6 +104,7 @@
 
   void removeReference();
 
+  virtual size_t alloc_size() const;
 
   /* -------------------   General Methods for Items ------------------------- */
 

=== modified file 'src/store/naive/atomic_items.cpp'
--- src/store/naive/atomic_items.cpp	2012-07-12 17:29:55 +0000
+++ src/store/naive/atomic_items.cpp	2012-07-13 00:33:23 +0000
@@ -43,6 +43,7 @@
 #include "tree_id.h"
 
 #include "util/ascii_util.h"
+#include "util/mem_sizeof.h"
 #include "util/string_util.h"
 #include "util/utf8_util.h"
 
@@ -381,6 +382,14 @@
 }
 
 
+size_t UserTypedAtomicItem::alloc_size() const
+{
+  return  AtomicItem::alloc_size()
+        + ztd::alloc_sizeof( theBaseItem )
+        + ztd::alloc_sizeof( theTypeName );
+}
+
+
 /*******************************************************************************
   class UntypedAtomicItem
 ********************************************************************************/
@@ -571,6 +580,12 @@
 }
 
 
+size_t UntypedAtomicItem::alloc_size() const
+{
+  return AtomicItem::alloc_size() + ztd::alloc_sizeof( theValue );
+}
+
+
 bool UntypedAtomicItem::equals(
     const store::Item* other,
     long timezone,
@@ -679,6 +694,15 @@
 }
 
 
+size_t QNameItem::alloc_size() const
+{
+  return  AtomicItem::alloc_size()
+        + ztd::alloc_sizeof( theNamespace )
+        + ztd::alloc_sizeof( thePrefix )
+        + ztd::alloc_sizeof( theLocal );
+}
+
+
 store::Item* QNameItem::getType() const
 {
   return GET_STORE().theSchemaTypeNames[store::XS_QNAME];
@@ -816,6 +840,12 @@
 }
 
 
+size_t NotationItem::alloc_size() const
+{
+  return ztd::mem_sizeof( *theQName );
+}
+
+
 store::Item* NotationItem::getType() const
 {
   return GET_STORE().theSchemaTypeNames[store::XS_NOTATION];
@@ -869,6 +899,12 @@
 }
 
 
+size_t AnyUriItem::alloc_size() const
+{
+  return AtomicItem::alloc_size() + ztd::alloc_sizeof( theValue );
+}
+
+
 bool AnyUriItem::getEBV() const
 {
   return ! (theValue == "");
@@ -1609,10 +1645,21 @@
   }
 }
 
+size_t StructuralAnyUriItem::alloc_size() const
+{
+  return AnyUriItem::alloc_size() + ztd::alloc_sizeof( theOrdPath );
+}
+
 
 /*******************************************************************************
   class StringItem
 ********************************************************************************/
+
+size_t StringItem::alloc_size() const
+{
+  return AtomicItem::alloc_size() + ztd::alloc_sizeof( theValue );
+}
+
 store::Item* StringItem::getType() const
 {
   return GET_STORE().theSchemaTypeNames[store::XS_STRING];
@@ -2402,6 +2449,12 @@
   class DecimalItem
 ********************************************************************************/
 
+size_t DecimalItem::alloc_size() const
+{
+  return AtomicItem::alloc_size() + ztd::alloc_sizeof( theValue );
+}
+
+
 store::Item* DecimalItem::getType() const
 {
   return GET_STORE().theSchemaTypeNames[store::XS_DECIMAL];
@@ -2451,6 +2504,14 @@
   class IntegerItemImpl
 ********************************************************************************/
 
+#ifdef ZORBA_WITH_BIG_INTEGER
+size_t IntegerItemImpl::alloc_size() const
+{
+  return ztd::alloc_size( theValue );
+}
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
+
 long IntegerItemImpl::compare( Item const *other, long,
                                const XQPCollator* ) const {
   try
@@ -2557,6 +2618,15 @@
 /*******************************************************************************
   class NonPositiveIntegerItem
 ********************************************************************************/
+
+#ifdef ZORBA_WITH_BIG_INTEGER
+size_t NonPositiveIntegerItem::alloc_size() const
+{
+  return ztd::alloc_size( theValue );
+}
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
+
 long NonPositiveIntegerItem::compare( Item const *other, long,
                                       const XQPCollator* ) const {
   try
@@ -2669,6 +2739,14 @@
 /*******************************************************************************
   class NonNegativeIntegerItem
 ********************************************************************************/
+
+#ifdef ZORBA_WITH_BIG_INTEGER
+size_t NonNegativeIntegerItem::alloc_size() const
+{
+  return ztd::alloc_size( theValue );
+}
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
 long NonNegativeIntegerItem::compare( Item const *other, long,
                                       const XQPCollator* ) const {
   try
@@ -3330,6 +3408,12 @@
 /*******************************************************************************
   class Base64BinaryItem
 ********************************************************************************/
+
+size_t Base64BinaryItem::alloc_size() const
+{
+  return AtomicItem::alloc_size() + ztd::alloc_sizeof( theValue );
+}
+
 bool
 Base64BinaryItem::equals(
       const store::Item* other,
@@ -3585,6 +3669,13 @@
 /*******************************************************************************
   class HexBinaryItem
 ********************************************************************************/
+
+size_t HexBinaryItem::alloc_size() const
+{
+  return theValue.size();
+}
+
+
 store::Item* HexBinaryItem::getType() const
 {
   return GET_STORE().theSchemaTypeNames[store::XS_HEXBINARY];
@@ -3627,13 +3718,16 @@
 /*******************************************************************************
   class ErrorItem
 ********************************************************************************/
+
 ErrorItem::~ErrorItem()
 {
-  if (theError)
-  {
-    delete theError;
-    theError = NULL;
-  }
+  delete theError;
+}
+
+
+size_t ErrorItem::alloc_size() const
+{
+  return theError ? ztd::mem_sizeof( *theError ) : 0;
 }
 
 

=== modified file 'src/store/naive/atomic_items.h'
--- src/store/naive/atomic_items.h	2012-07-12 17:29:55 +0000
+++ src/store/naive/atomic_items.h	2012-07-13 00:33:23 +0000
@@ -123,6 +123,8 @@
     return theBaseItem->hash(timezone, collation);
   }
 
+  size_t alloc_size() const;
+
   bool equals(
         const store::Item* other,
         long timezone = 0,
@@ -310,6 +312,8 @@
 
   uint32_t hash(long timezone = 0, const XQPCollator* aCollation = 0) const;
 
+  size_t alloc_size() const;
+
   bool equals(
         const store::Item* other,
         long timezone = 0,
@@ -382,6 +386,8 @@
 public:
   virtual ~QNameItem() {}
 
+  size_t alloc_size() const;
+
   // zorba::store::Item interface.
   bool equals(const store::Item* item,
               long timezone = 0,
@@ -554,6 +560,8 @@
       long timezone = 0,
       const XQPCollator* aCollation = 0) const;
 
+  size_t alloc_size() const;
+
   zstring getStringValue() const;
 
   void getStringValue2(zstring& val) const;
@@ -608,6 +616,8 @@
     return item->getString() == theValue;
   }
 
+  size_t alloc_size() const;
+
   long compare(
         const Item* other,
         long timezone = 0,
@@ -730,6 +740,8 @@
   StructuralAnyUriItem() {}
 
 public:
+  size_t alloc_size() const;
+
   bool
   isAncestor(const store::Item_t&) const;
 
@@ -820,6 +832,7 @@
   StringItem() {}
 
 public:
+  size_t alloc_size() const;
 
   virtual store::SchemaTypeCode getTypeCode() const { return store::XS_STRING; }
 
@@ -1379,6 +1392,8 @@
   DecimalItem() {}
 
 public:
+  size_t alloc_size() const;
+
   xs_decimal getDecimalValue() const { return theValue; }
 
   store::SchemaTypeCode getTypeCode() const { return store::XS_DECIMAL; }
@@ -1454,6 +1469,10 @@
   IntegerItemImpl() {}
 
 public:
+#ifdef ZORBA_WITH_BIG_INTEGER
+  size_t alloc_size() const;
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
   xs_decimal getDecimalValue() const;
 
   xs_integer getIntegerValue() const { return theValue; }
@@ -1507,6 +1526,10 @@
   NonPositiveIntegerItem() {}
 
 public:
+#ifdef ZORBA_WITH_BIG_INTEGER
+  size_t alloc_size() const;
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
   xs_decimal getDecimalValue() const;
 
   xs_integer getIntegerValue() const;
@@ -1580,6 +1603,10 @@
   NonNegativeIntegerItem() {}
 
 public:
+#ifdef ZORBA_WITH_BIG_INTEGER
+  size_t alloc_size() const;
+#endif /* ZORBA_WITH_BIG_INTEGER */
+
   xs_decimal getDecimalValue() const;
 
   xs_integer getIntegerValue() const;
@@ -1731,7 +1758,7 @@
   friend class AtomicItem;
 
 protected:
-  int32_t theValue;
+  xs_int theValue;
 
 protected:
   IntItem(xs_int aValue) : theValue(aValue) {}
@@ -1747,7 +1774,7 @@
 
   xs_long getLongValue() const { return static_cast<xs_long>(theValue); }
 
-  int32_t getIntValue() const { return theValue; }
+  xs_int getIntValue() const { return theValue; }
 
   store::SchemaTypeCode getTypeCode() const { return store::XS_INT; }
 
@@ -2404,6 +2431,8 @@
   }
 
 public:
+  size_t alloc_size() const;
+
   const char* getBase64BinaryValue(size_t& data) const;
 
   store::SchemaTypeCode getTypeCode() const { return store::XS_BASE64BINARY; }
@@ -2524,6 +2553,8 @@
   HexBinaryItem() {}
 
 public:
+  size_t alloc_size() const;
+
   xs_hexBinary getHexBinaryValue() const { return theValue; }
 
   store::SchemaTypeCode getTypeCode() const { return store::XS_HEXBINARY; }
@@ -2579,6 +2610,8 @@
 public:
   virtual ~ErrorItem();
 
+  size_t alloc_size() const;
+
   ZorbaException* getError() const { return theError; }
 
   zstring show() const;

=== modified file 'src/store/naive/item.cpp'
--- src/store/naive/item.cpp	2012-07-12 17:29:55 +0000
+++ src/store/naive/item.cpp	2012-07-13 00:33:23 +0000
@@ -225,6 +225,10 @@
 #endif
 }
 
+size_t Item::alloc_size() const {
+  return 0;
+}
+
 
 Item::ItemKind Item::getKind() const
 {

=== modified file 'src/store/naive/node_items.cpp'
--- src/store/naive/node_items.cpp	2012-07-12 17:29:55 +0000
+++ src/store/naive/node_items.cpp	2012-07-13 00:33:23 +0000
@@ -45,6 +45,7 @@
 #include "dataguide.h"
 #include "node_factory.h"
 
+#include "util/mem_sizeof.h"
 #include "util/stl_util.h"
 #include "util/string_util.h"
 
@@ -936,6 +937,10 @@
   }
 }
 
+size_t ConnectorNode::alloc_size() const
+{
+  return XmlNode::alloc_size() + ztd::alloc_sizeof( theNode );
+}
 
 /*******************************************************************************
 
@@ -1012,6 +1017,12 @@
   }
 }
 
+///////////////////////////////////////////////////////////////////////////////
+
+size_t OrdPathNode::alloc_size() const
+{
+  return XmlNode::alloc_size() + ztd::alloc_sizeof( theOrdPath );
+}
 
 /*******************************************************************************
 
@@ -1172,6 +1183,7 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
 bool
 OrdPathNode::getDescendantNodeByOrdPath(
     const OrdPath& aOrdPath,
@@ -1462,6 +1474,13 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t InternalNode::alloc_size() const
+{
+  return OrdPathNode::alloc_size() + ztd::alloc_sizeof( theNodes );
+}
+
+
 const OrdPath* InternalNode::getFirstChildOrdPathAfter(csize pos) const
 {
   assert((pos == 0 && numChildren() == 0) || pos < numChildren());
@@ -1777,6 +1796,13 @@
 }
 
 
+size_t DocumentNode::alloc_size() const
+{
+  return  InternalNode::alloc_size()
+        + ztd::alloc_sizeof( theBaseUri )
+        + ztd::alloc_sizeof( theDocUri );
+}
+
 /*******************************************************************************
 
 ********************************************************************************/
@@ -2493,6 +2519,16 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t ElementNode::alloc_size() const
+{
+  return InternalNode::alloc_size()
+#ifdef EMBEDED_TYPE
+      + ztd::alloc_sizeof( theTypeName )
+#endif
+      + ztd::alloc_sizeof( theName );
+}
+
 #ifdef EMBEDED_TYPE
 store::Item* ElementNode::getType() const
 {
@@ -3622,6 +3658,18 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t AttributeNode::alloc_size() const
+{
+  return  OrdPathNode::alloc_size()
+        + ztd::alloc_sizeof( theName )
+#ifdef EMBEDED_TYPE
+        + ztd::alloc_sizeof( theTypeName )
+#endif
+        + ztd::alloc_sizeof( theTypedValue );
+}
+
+
 XmlNode* AttributeNode::copyInternal(
     InternalNode* rootParent,
     InternalNode* parent,
@@ -4115,6 +4163,18 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t TextNode::alloc_size() const
+{
+  return  base_type::alloc_size()
+        + (isTyped() ?
+            ztd::alloc_sizeof( theContent.getValue() ) :
+            ztd::alloc_sizeof( theContent.getText() )
+        );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 XmlNode* TextNode::copyInternal(
     InternalNode* rootParent,
     InternalNode* parent,
@@ -4745,6 +4805,17 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t PiNode::alloc_size() const
+{
+  return  OrdPathNode::alloc_size()
+        + ztd::alloc_sizeof( theTarget )
+        + ztd::alloc_sizeof( theContent )
+        + ztd::alloc_sizeof( theName );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 XmlNode* PiNode::copyInternal(
     InternalNode* rootParent,
     InternalNode* parent,
@@ -4879,6 +4950,14 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t CommentNode::alloc_size() const
+{
+  return  OrdPathNode::alloc_size() + ztd::alloc_sizeof( theContent );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
 XmlNode* CommentNode::copyInternal(
     InternalNode* rootParent,
     InternalNode* parent,

=== modified file 'src/store/naive/node_items.h'
--- src/store/naive/node_items.h	2012-07-12 17:29:55 +0000
+++ src/store/naive/node_items.h	2012-07-13 00:33:23 +0000
@@ -576,6 +576,8 @@
       const XmlNode* child);
 
 public:
+  size_t alloc_size() const;
+
   XmlNode* getNode() const { return theNode.getp(); }
 
   store::Item* getNodeName() const { return theNode->getNodeName(); }
@@ -638,6 +640,8 @@
   virtual ~OrdPathNode() {}
 
 public:
+  size_t alloc_size() const;
+
   const OrdPath& getOrdPath() const { return theOrdPath; }
 
   OrdPath& getOrdPath() { return theOrdPath; }
@@ -748,6 +752,8 @@
   // SimpleStore Methods
   //
 
+  size_t alloc_size() const;
+
   // To be used by the loader ONLY!
   NodeVector& nodes() { return theNodes; }
 
@@ -888,6 +894,8 @@
   // Item methods
   //
 
+  size_t alloc_size() const;
+
   store::Item* getType() const;
 
   void getDocumentURI(zstring& uri) const { uri = theDocUri; }
@@ -977,6 +985,8 @@
   //
   // Item methods
   //
+  size_t alloc_size() const;
+
   store::Item* getNodeName() const { return theName.getp(); }
 
   store::Item* getType() const;
@@ -1164,6 +1174,8 @@
   // Item methods
   //
 
+  size_t alloc_size() const;
+
   store::Item* getNodeName() const { return theName.getp(); }
 
   store::Item* getType() const;
@@ -1258,11 +1270,12 @@
 
 ********************************************************************************/
 #ifdef TEXT_ORDPATH
-class TextNode : public OrdPathNode
+class TextNode : public OrdPathNode {
+  typedef OrdPathNode base_type;
 #else
-class TextNode : public XmlNode
+class TextNode : public XmlNode {
+  typedef XmlNode base_type;
 #endif
-{
   friend class XmlNode;
   friend class InternalNode;
   friend class DocumentDagNode;
@@ -1312,6 +1325,8 @@
   // Item methods
   //
 
+  size_t alloc_size() const;
+
   store::Item* getType() const;
 
   void getTypedValue(store::Item_t& val, store::Iterator_t& iter) const;
@@ -1442,6 +1457,8 @@
   PiNode() {}
 
 public:
+  size_t alloc_size() const;
+
   XmlNode* copyInternal(
         InternalNode* rootParent,
         InternalNode* parent,
@@ -1505,6 +1522,8 @@
   CommentNode() {}
 
 public:
+  size_t alloc_size() const;
+
   XmlNode* copyInternal(
         InternalNode* rootParent,
         InternalNode* parent,

=== modified file 'src/store/naive/ordpath.cpp'
--- src/store/naive/ordpath.cpp	2012-07-12 17:29:55 +0000
+++ src/store/naive/ordpath.cpp	2012-07-13 00:33:23 +0000
@@ -329,12 +329,17 @@
 /*******************************************************************************
 
 ********************************************************************************/
+
+size_t OrdPath::alloc_size() const
+{
+  return isRemote() ? getRemoteByteLength() : 0;
+}
+
 bool OrdPath::isRoot() const
 {
   return isLocal() && theBuffer.local[0] == 0x40;
 }
 
-
 /*******************************************************************************
 
 ********************************************************************************/

=== modified file 'src/store/naive/ordpath.h'
--- src/store/naive/ordpath.h	2012-07-12 17:29:55 +0000
+++ src/store/naive/ordpath.h	2012-07-13 00:33:23 +0000
@@ -65,6 +65,8 @@
     MAX_BIT_LEN = MAX_BYTE_LEN * 8
   };
 
+  size_t alloc_size() const;
+
 protected:
   static const ulong MAX_EMBEDDED_BYTE_LEN = 8;
   static const ulong MAX_EMBEDDED_BIT_LEN = MAX_EMBEDDED_BYTE_LEN * 8 - 1;

=== modified file 'src/unit_tests/CMakeLists.txt'
--- src/unit_tests/CMakeLists.txt	2012-07-12 17:29:55 +0000
+++ src/unit_tests/CMakeLists.txt	2012-07-13 00:33:23 +0000
@@ -18,6 +18,7 @@
   test_base64_streambuf.cpp
   test_fs_iterator.cpp
   test_json_parser.cpp
+  test_mem_sizeof.cpp
   test_string.cpp
   test_uri.cpp
   unit_tests.cpp

=== added file 'src/unit_tests/test_mem_sizeof.cpp'
--- src/unit_tests/test_mem_sizeof.cpp	1970-01-01 00:00:00 +0000
+++ src/unit_tests/test_mem_sizeof.cpp	2012-07-13 00:33:23 +0000
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <iostream>
+#include <string>
+
+#include "util/cxx_util.h"
+#include "util/mem_sizeof.h"
+
+using namespace std;
+using namespace zorba;
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int failures;
+
+static bool assert_true( char const *expr, int line, bool result ) {
+  if ( !result ) {
+    cout << "FAILED, line " << line << ": " << expr << endl;
+    ++failures;
+  }
+  return result;
+}
+
+#define ASSERT_TRUE( EXPR ) assert_true( #EXPR, __LINE__, !!(EXPR) )
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_int() {
+  int i;
+  ASSERT_TRUE( ztd::mem_sizeof( i ) == sizeof( i ) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_map_string_int() {
+  typedef map<string,int> map_type;
+  map_type m;
+  string const key( "a" );
+  m[ key ] = 1;
+
+  size_t const expected_size = sizeof( m )
+    + sizeof( map_type::value_type ) + key.size();
+
+  ASSERT_TRUE( ztd::mem_sizeof( m ) == expected_size );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct point {
+  int x, y, z;
+};
+
+static void test_pod() {
+  point p;
+  ASSERT_TRUE( ztd::mem_sizeof( p ) == sizeof( p ) );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_pointer() {
+  int *p = nullptr;
+  ASSERT_TRUE( ztd::mem_sizeof( p ) == sizeof( p ) );
+  p = new int;
+  ASSERT_TRUE( ztd::mem_sizeof( p ) == sizeof( p ) + sizeof( int ) );
+  delete p;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+template<class StringType>
+static void test_string_empty() {
+  StringType const s;
+  ASSERT_TRUE( ztd::mem_sizeof( s ) == sizeof( s ) );
+}
+
+template<class StringType>
+static void test_string_not_empty() {
+  StringType const s( "hello" );
+  ASSERT_TRUE( ztd::mem_sizeof( s ) == sizeof( s ) + s.size() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_vector_int() {
+  typedef vector<int> vector_type;
+  vector_type v;
+  v.push_back( 1 );
+
+  size_t const expected_size = sizeof( v ) + sizeof( vector_type::value_type );
+
+  ASSERT_TRUE( ztd::mem_sizeof( v ) == expected_size );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+struct my_base {
+  virtual size_t alloc_size() const {
+    return ztd::alloc_sizeof( s_ ) + ztd::alloc_sizeof( t_ );
+  }
+
+  string s_, t_;
+};
+
+struct my_derived : my_base {
+  my_derived( string const &s ) : s_( s ) { }
+
+  size_t alloc_size() const {
+    return my_base::alloc_size() + ztd::alloc_sizeof( s_ );
+  }
+
+  string s_;
+};
+
+static void test_base_empty() {
+  my_base b;
+  ASSERT_TRUE( ztd::mem_sizeof( b ) == sizeof( b ) );
+}
+
+static void test_derived_not_empty() {
+  string const s( "hello" );
+  my_derived d( s );
+  ASSERT_TRUE( ztd::mem_sizeof( d ) == sizeof( d ) + s.size() );
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+namespace UnitTests {
+
+int test_mem_sizeof( int, char*[] ) {
+  test_int();
+  test_pointer();
+  test_pod();
+
+  test_string_empty<string>();
+  test_string_not_empty<string>();
+  test_string_empty<zstring>();
+  test_string_not_empty<zstring>();
+
+  test_map_string_int();
+  test_vector_int();
+
+  test_base_empty();
+  test_derived_not_empty();
+
+  cout << failures << " test(s) failed\n";
+  return failures ? 1 : 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace UnitTests
+} // namespace zorba
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/unit_tests/unit_test_list.h'
--- src/unit_tests/unit_test_list.h	2012-07-12 17:29:55 +0000
+++ src/unit_tests/unit_test_list.h	2012-07-13 00:33:23 +0000
@@ -33,6 +33,7 @@
   int test_icu_streambuf( int, char*[] );
 #endif /* ZORBA_NO_ICU */
   int test_json_parser( int, char*[] );
+  int test_mem_sizeof( int, char*[] );
   int test_string( int, char*[] );
 #ifndef ZORBA_NO_FULL_TEXT
   int test_stemmer( int, char*[] );

=== modified file 'src/unit_tests/unit_tests.cpp'
--- src/unit_tests/unit_tests.cpp	2012-07-12 17:29:55 +0000
+++ src/unit_tests/unit_tests.cpp	2012-07-13 00:33:23 +0000
@@ -43,6 +43,7 @@
 #ifndef ZORBA_NO_ICU
   libunittests["icu_streambuf"] = test_icu_streambuf;
 #endif /* ZORBA_NO_ICU */
+  libunittests["mem_sizeof"] = test_mem_sizeof;
   libunittests["json_parser"] = test_json_parser;
   libunittests["string"] = test_string;
 #ifndef ZORBA_NO_FULL_TEXT

=== added file 'src/util/mem_sizeof.h'
--- src/util/mem_sizeof.h	1970-01-01 00:00:00 +0000
+++ src/util/mem_sizeof.h	2012-07-13 00:33:23 +0000
@@ -0,0 +1,390 @@
+/*
+ * Copyright 2006-2008 The FLWOR Foundation.
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ZORBA_MEM_SIZEOF
+#define ZORBA_MEM_SIZEOF
+
+#include <cstring>
+#include <map>
+#include <set>
+#include <stack>
+#include <string>
+#include <vector>
+
+#include <zorba/internal/ztd.h>
+#include <zorba/internal/unique_ptr.h>
+
+#include "util/stl_util.h"
+#include "util/unordered_map.h"
+#include "util/unordered_set.h"
+#include "zorbatypes/rchandle.h"
+#include "zorbatypes/zstring.h"
+
+///////////////////////////////////////////////////////////////////////////////
+
+namespace zorba {
+namespace ztd {
+
+/**
+ * \file
+ * This file provides the \c mem_sizeof() function that returns the total
+ * amount of memory an object is using including any dynamically allocated
+ * memory it has pointers to.  Hence \c mem_sizeof() takes a reference to an
+ * actual object at run-time rather than only a type at compile-time like the
+ * build-in C++ \c sizeof operator does.
+ *
+ * For all built-in types as well as arrays, structs, classes, and unions
+ * composed of only built-in types, <code>mem_sizeof(t) == sizeof(t)</code>.
+ * However, for a \c std::string \s,
+ * <code>mem_sizeof(s) == sizeof(s) + s.size()</code>.
+ *
+ * To implement this, there has to be a distinction between
+ * <em>memory size</em> (<code>mem_sizeof()</code)
+ * and <em>allocation size</em> (<code>alloc_sizeof()</code).
+ * The latter is how much \e additional memory has been dynamically allocated
+ * by an object (if any).
+ *
+ * For all objects of built-in types as well as arrays, structs, classes, and
+ * unions composed of only built-in types, <code>alloc_sizeof(t) == 0</code>
+ * because those objects don't have any additional dynamically allocated memory.
+ *
+ * For structs and classes that \e do have additional dynamically allocated
+ * memory, there has to be a way for \c alloc_sizeof() to be able to know how
+ * much memory.
+ * This can be accomplished by two different methods:
+ *  <ol>
+ *    <li>
+ *      Template partial specialization of \c size_traits.
+ *    </li>
+ *    <li>
+ *      Adding an \c alloc_size() member function to your class.
+ *    </li>
+ *  </ol>
+ * Template partial specialization must be used
+ * when you can not (or do not want to) modify a class.
+ * However, this method may not always be able to report
+ * all the dynamically allocated memory an object may be using.
+ * It also has the code for a class and its template specialization
+ * in different places in the code.
+ *
+ * Adding an \c alloc_size() member function
+ * allows you to report the precise amount of memory an object is using
+ * and also has the code directly in the class.
+ * However, it is intrusive and adds a (possibly virtual) function.
+ *
+ * An example of template partial specialization is for \c std::string.
+ * Since the source code for \c std::string can not be (easily) modified,
+ * you must use template partial specialization for it.
+ * \code
+ *  template<>
+ *  struct size_traits<std::string> {
+ *    static size_t alloc_sizeof( std::string const &s ) {
+ *      return s.size();
+ *    }
+ *  };
+ * \endcode
+ * This specialization, however, does not report all the memory
+ * dynamically allocated by some implementations of \c std::string.
+ * Some implementations use an additional "rep" object.
+ * There's no way to determine whether a given implemenation uses one
+ * much less how much memory it uses programatically,
+ * but it's the best that can be done.
+ *
+ * An example of adding an \c alloc_size() member function is:
+ * \code
+ *  class my_class {
+ *  public:
+ *    // ...
+ *    size_t alloc_size() const {
+ *      return alloc_sizeof( s ) + alloc_sizeof( p );
+ *    }
+ *  private:
+ *    int i;
+ *    std::string s;
+ *    some_other_class *p;
+ *  };
+ * \endcode
+ * Notes:
+ *  <ul>
+ *    <li>
+ *      Doing \c alloc_sizeof(i) isn't necessary since it returns 0.
+ *      (You could do it if you wanted to for the sake of completeness
+ *      without incurring any run-time penalty
+ *      since the implementation of \c alloc_sizeof() for built-in C++ types
+ *      is an \c inline function that always returns 0.
+ *      The function will be optimized away by the compiler.)
+ *    </li>
+ *    <li>
+ *      Calling \c alloc_sizeof(p) for a pointer automatically dereferences it
+ *      (if it's non-null) and adds in the \c mem_sizeof(*p).
+ *    </li>
+ *  </ul>
+ *
+ * If your class has derived classes, then:
+ *  <ol>
+ *    <li>
+ *      \c alloc_size() must be virtual.
+ *    </li>
+ *    <li>
+ *      Derived classes must also implement of \c alloc_size()
+ *      and they must call their base class's implementations.
+ *    </li>
+ *  </ol>
+ * For example:
+ * \code
+ *  class my_derived_class : public my_class {
+ *  public:
+ *    // ...
+ *    size_t alloc_size() const {
+ *      return my_class::alloc_size() + alloc_size( u );
+ *    }
+ *  private:
+ *    std::string u;
+ *  };
+ * \endcode
+ */
+
+///////////////////////////////////////////////////////////////////////////////
+
+/**
+ * Tests the given type to see if it's a class that has a member function
+ * named \c alloc_size having the signature:
+ * \code
+ *  size_t (T::*)() const
+ * \endcode
+ * @tparam T The type to test.
+ */
+template<typename T>
+class has_alloc_size : zorba::internal::ztd::sfinae_base {
+  template<typename SignatureType,SignatureType> struct type_check;
+
+  template<typename U>
+  static yes& test( type_check<size_t (U::*)() const,&U::alloc_size>* );
+
+  template<typename U>
+  static no& test( ... );
+
+public:
+  static bool const value = sizeof( test<T>(0) ) == sizeof( yes );
+};
+
+/**
+ * Size traits for classes that have an \c alloc_size() member function having
+ * the signature:
+ * \code
+ *  size_t (T::*)() const
+ * \endcode
+ *
+ * @tparam T The type to use.
+ */
+template<typename T,bool = has_alloc_size<T>::value>
+struct size_traits {
+  static size_t alloc_sizeof( T const &t ) {
+    return t.alloc_size();
+  }
+};
+
+/**
+ * Specialization for any non-pointer type.
+ * @tparam T The type to use.
+ */
+template<typename T>
+struct size_traits<T,false> {
+  static size_t alloc_sizeof( T const& ) {
+    return 0;
+  }
+};
+
+/**
+ * Gets the size of all the object's additional data.
+ * It does \e not include the size of the object itself.
+ *
+ * @tparam T The type to get the data size of.
+ * @param t An instance of \a T to get the data size of.
+ */
+template<typename T>
+inline size_t alloc_sizeof( T const &t ) {
+  return size_traits<T>::alloc_sizeof( t );
+}
+
+/**
+ * Gets the total memory size of an object.
+ *
+ * @tparam T The type to get the memory size of.
+ * @param t An instance of \a T to get the memory size of.
+ */
+template<typename T>
+inline size_t mem_sizeof( T const &t ) {
+  return sizeof( T ) + alloc_sizeof( t );
+}
+
+/**
+ * Specialization for pointer types.
+ * @tparam T A pointer type.
+ */
+template<typename T>
+struct size_traits<T*,false> {
+  static size_t alloc_sizeof( T *p ) {
+    return p ? mem_sizeof( *p ) : 0;
+  }
+};
+
+/**
+ * Specialization for <code>char const*</code>.
+ */
+template<>
+struct size_traits<char const*> {
+  static size_t alloc_sizeof( char const *s ) {
+    return s ? std::strlen( s ) : 0;
+  }
+};
+
+////////// C++ Specializations ////////////////////////////////////////////////
+
+/**
+ * Specialization for std::string.
+ */
+template<>
+struct size_traits<std::string> {
+  static size_t alloc_sizeof( std::string const &s ) {
+    return s.size();
+  }
+};
+
+/**
+ * Size traits for a MapType.
+ * (This is a base class used by other specializations.)
+ */
+template<class MapType>
+struct map_size_traits {
+  static size_t alloc_sizeof( MapType const &m ) {
+    size_t const padding =
+        sizeof( typename MapType::value_type )
+      - sizeof( typename MapType::key_type )
+      - sizeof( typename MapType::mapped_type );
+    size_t total_size = m.size() * padding;
+    FOR_EACH( typename MapType, i, m )
+      total_size += mem_sizeof( i->first ) + mem_sizeof( i->second );
+    return total_size;
+  }
+};
+
+/**
+ * Specialization for std::map.
+ */
+template<typename K,typename V,typename Comp,class Alloc>
+struct size_traits<std::map<K,V,Comp,Alloc>,false> :
+  map_size_traits< std::map<K,V,Comp,Alloc> >
+{
+};
+
+/**
+ * Specialization for std::unordered_map.
+ */
+template<typename K,typename V,class Hash,class Equal,class Alloc>
+struct size_traits<std::unordered_map<K,V,Hash,Equal,Alloc>,false> :
+  map_size_traits< std::unordered_map<K,V,Hash,Equal,Alloc> >
+{
+};
+
+/**
+ * Size traits for a SequenceType.
+ * (This is a base class used by other specializations.)
+ */
+template<class SequenceType>
+struct sequence_size_traits {
+  static size_t alloc_sizeof( SequenceType const &s ) {
+    size_t total_size = 0;
+    FOR_EACH( typename SequenceType, i, s )
+      total_size += mem_sizeof( *i );
+    return total_size;
+  }
+};
+
+/**
+ * Specialization for std::set.
+ */
+template<typename T,class Comp,class Alloc>
+struct size_traits<std::set<T,Comp,Alloc>,false> :
+  sequence_size_traits< std::set<T,Comp,Alloc> >
+{
+};
+
+/**
+ * Specialization for std::stack.
+ */
+template<typename T,class Container>
+struct size_traits<std::stack<T,Container>,false> :
+  sequence_size_traits< std::stack<T,Container> >
+{
+};
+
+/**
+ * Specialization for std::unique_ptr.
+ */
+template<typename T,class D>
+struct size_traits<std::unique_ptr<T,D>,false> {
+  static size_t alloc_sizeof( std::unique_ptr<T,D> const &p ) {
+    return p ? mem_sizeof( *p ) : 0;
+  }
+};
+
+/**
+ * Specialization for std::unordered_set.
+ */
+template<typename K,class Hash,class Equal,class Alloc>
+struct size_traits<std::unordered_set<K,Hash,Equal,Alloc>,false> :
+  sequence_size_traits< std::unordered_set<K,Hash,Equal,Alloc> >
+{
+};
+
+/**
+ * Specialization for std::vector.
+ */
+template<typename T,class Alloc>
+struct size_traits<std::vector<T,Alloc>,false> :
+  sequence_size_traits< std::vector<T,Alloc> >
+{
+};
+
+////////// Zorba specializations //////////////////////////////////////////////
+
+/**
+ * Specialization for rstring.
+ */
+template<class RepType>
+struct size_traits<rstring<RepType>,false> {
+  static size_t alloc_sizeof( rstring<RepType> const &s ) {
+    return s.size();
+  }
+};
+
+/**
+ * Specialization for rchandle.
+ */
+template<class T>
+struct size_traits<rchandle<T>,false> {
+  static size_t alloc_sizeof( rchandle<T> const &h ) {
+    return h.get() ? mem_sizeof( *h ) : 0;
+  }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+} // namespace ztd
+} // namespace zorba
+#endif /* ZORBA_MEM_SIZEOF */
+/* vim:set et sw=2 ts=2: */

=== modified file 'src/zorbatypes/decimal.cpp'
--- src/zorbatypes/decimal.cpp	2012-07-12 17:29:55 +0000
+++ src/zorbatypes/decimal.cpp	2012-07-13 00:33:23 +0000
@@ -368,6 +368,10 @@
 
 ////////// miscellaneous //////////////////////////////////////////////////////
 
+size_t Decimal::alloc_size() const {
+  return value_.significant_digits();
+}
+
 uint32_t Decimal::hash( value_type const &value ) {
   char buf[1024];
   char *bufp = value.exponent() + 3 > 1024 ?

=== modified file 'src/zorbatypes/decimal.h'
--- src/zorbatypes/decimal.h	2012-07-12 17:29:55 +0000
+++ src/zorbatypes/decimal.h	2012-07-13 00:33:23 +0000
@@ -211,6 +211,8 @@
 
   ////////// miscellaneous ////////////////////////////////////////////////////
 
+  size_t alloc_size() const;
+
   bool is_xs_int() const;
   bool is_xs_integer() const;
   bool is_xs_long() const;

=== modified file 'src/zorbatypes/integer.cpp'
--- src/zorbatypes/integer.cpp	2012-07-12 17:29:55 +0000
+++ src/zorbatypes/integer.cpp	2012-07-13 00:33:23 +0000
@@ -374,6 +374,10 @@
 #endif /* ZORBA_WITH_BIG_INTEGER */
 
 #ifdef ZORBA_WITH_BIG_INTEGER
+size_t IntegerImpl::alloc_size() const {
+  return value_.significant_digits();
+}
+
 uint32_t IntegerImpl::hash() const {
   return Decimal::hash( value_ );
 }

=== modified file 'src/zorbatypes/integer.h'
--- src/zorbatypes/integer.h	2012-07-12 17:29:55 +0000
+++ src/zorbatypes/integer.h	2012-07-13 00:33:23 +0000
@@ -116,9 +116,9 @@
 
   /////////////////////////////////////////////////////////////////////////////
 
-  #ifndef ZORBA_WITH_BIG_INTEGER
+#ifndef ZORBA_WITH_BIG_INTEGER
   IntType& get_value() { return value_; }
-  #endif
+#endif /* ZORBA_WITH_BIG_INTEGER */
 
   ////////// assignment operators /////////////////////////////////////////////
 
@@ -445,6 +445,9 @@
 
   ////////// miscellaneous ////////////////////////////////////////////////////
 
+#ifdef ZORBA_WITH_BIG_INTEGER
+  size_t alloc_size() const;
+#endif /* ZORBA_WITH_BIG_INTEGER */
   int compare( IntegerImpl const& ) const;
   uint32_t hash() const;
   bool is_cxx_long() const;

-- 
Mailing list: https://launchpad.net/~zorba-coders
Post to     : zorba-coders@lists.launchpad.net
Unsubscribe : https://launchpad.net/~zorba-coders
More help   : https://help.launchpad.net/ListHelp

Reply via email to