You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2013/11/07 23:06:46 UTC

git commit: More tests and fixes.

Updated Branches:
  refs/heads/trunk 12e0385b5 -> 2d9ce2f36


More tests and fixes.

Project: http://git-wip-us.apache.org/repos/asf/activemq-cpp/repo
Commit: http://git-wip-us.apache.org/repos/asf/activemq-cpp/commit/2d9ce2f3
Tree: http://git-wip-us.apache.org/repos/asf/activemq-cpp/tree/2d9ce2f3
Diff: http://git-wip-us.apache.org/repos/asf/activemq-cpp/diff/2d9ce2f3

Branch: refs/heads/trunk
Commit: 2d9ce2f369d618c143430e33ead899ef01a14d5f
Parents: 12e0385
Author: Timothy Bish <ta...@gmai.com>
Authored: Thu Nov 7 17:06:37 2013 -0500
Committer: Timothy Bish <ta...@gmai.com>
Committed: Thu Nov 7 17:06:37 2013 -0500

----------------------------------------------------------------------
 activemq-cpp/src/main/decaf/lang/String.cpp     | 27 +++++++++-
 activemq-cpp/src/main/decaf/lang/String.h       | 40 ++++++++++++--
 activemq-cpp/src/test/decaf/lang/StringTest.cpp | 56 ++++++++++++++++++--
 activemq-cpp/src/test/decaf/lang/StringTest.h   |  4 ++
 activemq-cpp/src/test/testRegistry.cpp          |  8 +--
 5 files changed, 124 insertions(+), 11 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/2d9ce2f3/activemq-cpp/src/main/decaf/lang/String.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/lang/String.cpp b/activemq-cpp/src/main/decaf/lang/String.cpp
index ad9bb80..6070df0 100644
--- a/activemq-cpp/src/main/decaf/lang/String.cpp
+++ b/activemq-cpp/src/main/decaf/lang/String.cpp
@@ -337,7 +337,16 @@ const char* String::c_str() const {
         return (const char*) (contents->value.get() + contents->offset);
     }
 
-    throw UnsupportedOperationException(__FILE__, __LINE__, "Not yet implemented for offset values");
+    Contents* newContents = new Contents(contents->length);
+
+    System::arraycopy(contents->value.get(), contents->offset,
+                      newContents->value.get(), 0, contents->length);
+
+    Contents* oldContents = this->contents;
+    this->contents = newContents;
+    delete oldContents;
+
+    return contents->value.get();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -357,6 +366,22 @@ char String::charAt(int index) const {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+String String::compact() const {
+
+    // Empty String.
+    if (contents->value.length() == 0) {
+        return *this;
+    }
+
+    // Don't do anything if the string is already compact.
+    if (contents->value.length() > this->contents->length + 1) {
+        return String(contents->value.get(), contents->offset, contents->length);
+    }
+
+    return *this;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 int String::compareTo(const String& string) const {
 
     int o1 = contents->offset;

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/2d9ce2f3/activemq-cpp/src/main/decaf/lang/String.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/main/decaf/lang/String.h b/activemq-cpp/src/main/decaf/lang/String.h
index 8865dd8..722942b 100644
--- a/activemq-cpp/src/main/decaf/lang/String.h
+++ b/activemq-cpp/src/main/decaf/lang/String.h
@@ -32,14 +32,30 @@ namespace lang {
     class Contents;
 
     /**
-     * The String class represents an immutable sequence of chars.
+     * An immutable sequence of characters.
+     *
+     * This class is implemented using a char[]. The length of the array may exceed
+     * the length of the string. For example, the string "Hello" may be backed by
+     * the array {@code ['H', 'e', 'l', 'l', 'o', 'W'. 'o', 'r', 'l', 'd']} with
+     * offset 0 and length 5.
+     *
+     * Multiple strings can share the same char[] because strings are immutable.
+     *
+     * The substring method always returns a string that shares the backing array of
+     * its source string. Generally this is an optimization: fewer character arrays
+     * need to be allocated, and less copying is necessary. But this can also lead
+     * to unwanted heap retention. Taking a short substring of long string means that
+     * the long shared char[] won't be garbage until both strings are destroyed. This
+     * typically happens when parsing small substrings out of a large input. To avoid
+     * this where necessary, call the compact method which allocates a new array that
+     * is just big enough to store the String's content.
      *
      * @since 1.0
      */
     class DECAF_API String: public CharSequence {
     private:
 
-        Contents* contents;
+        mutable Contents* contents;
 
     public:
 
@@ -240,7 +256,11 @@ namespace lang {
 
         /**
          * Returns a const char* value to allow easier coexistence with standard c++
-         * string operations..
+         * string operations.
+         *
+         * This method can result in a compaction of the String's backing store into a
+         * new character array in order to return a pointer value that is guaranteed to
+         * be NULL terminated.
          *
          * @returns a const char* value for this String.
          */
@@ -249,6 +269,20 @@ namespace lang {
     public:
 
         /**
+         * If the String instance is holding a reference to a character array that is larger
+         * than the string's view of the backing store a new array is allocated and the
+         * characters from the substring this String represents are copied to the new backing
+         * store and returned in the resulting String object.
+         *
+         * This can free up heap memory when a String is holding a large array but only
+         * viewing a small portion of it and the original source String is no longer also
+         * maintaining a reference to the backing store.
+         *
+         * @returns a new String instance with a compacted backing store.
+         */
+        String compact() const;
+
+        /**
          * Compares two strings lexicographically. The comparison is based on the value
          * of each character in the strings. The character sequence represented by this
          * String is compared lexicographically to the character sequence represented by

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/2d9ce2f3/activemq-cpp/src/test/decaf/lang/StringTest.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/lang/StringTest.cpp b/activemq-cpp/src/test/decaf/lang/StringTest.cpp
index fea0248..604f211 100644
--- a/activemq-cpp/src/test/decaf/lang/StringTest.cpp
+++ b/activemq-cpp/src/test/decaf/lang/StringTest.cpp
@@ -83,6 +83,11 @@ void StringTest::testConstructorCString() {
         "Should have thrown an IndexOutOfBoundsException",
         test.charAt(5),
         IndexOutOfBoundsException);
+
+    CPPUNIT_ASSERT_THROW_MESSAGE(
+        "Should have thrown an NullPointerException",
+        String((const char*)NULL),
+        NullPointerException);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -206,6 +211,22 @@ void StringTest::testConstructorString() {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+void StringTest::testConstructorCharFill() {
+
+    String expected("AAAAA");
+    String input('A', 5);
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("String fill failed", expected, input);
+
+    CPPUNIT_ASSERT_MESSAGE("String should be empty", String('A', 0).isEmpty());
+
+    CPPUNIT_ASSERT_THROW_MESSAGE(
+        "Should have thrown an IndexOutOfBoundsException",
+        String('A', -1),
+        IndexOutOfBoundsException);
+}
+
+////////////////////////////////////////////////////////////////////////////////
 void StringTest::testAssignmentString() {
 
     String transient;
@@ -275,6 +296,26 @@ void StringTest::testAssignmentCString() {
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+void StringTest::testCompact() {
+
+    const String input("HelloWorld");
+    const String expected("World");
+
+    CPPUNIT_ASSERT_MESSAGE("Incorrect substring returned", expected.equals(input.substring(5)));
+    CPPUNIT_ASSERT_MESSAGE("not identical", expected.substring(0) == expected);
+
+    String subStr = input.substring(5);
+    CPPUNIT_ASSERT_MESSAGE("wrong length returned.", subStr.length() == 5);
+    String compacted = subStr.compact();
+    CPPUNIT_ASSERT_MESSAGE("wrong length returned.", compacted.length() == 5);
+    CPPUNIT_ASSERT_MESSAGE("Incorrect compacted string returned", expected.equals(compacted));
+
+    String empty;
+    empty = empty.compact();
+    CPPUNIT_ASSERT_MESSAGE("wrong length returned.", empty.isEmpty());
+}
+
+////////////////////////////////////////////////////////////////////////////////
 void StringTest::testIsEmpty() {
 
     String hw("HelloWorld");
@@ -453,15 +494,22 @@ void StringTest::testCStr() {
     String substr = hw.substring(5);
     String world = "World";
 
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid string returned", world, substr);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Invalid string returned",
+                                 std::string(world.c_str()), std::string(substr.c_str()));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 void StringTest::testEndsWith() {
     const String input("HelloWorld");
 
-    CPPUNIT_ASSERT_MESSAGE("Failed to find ending string", input.endsWith("ld"));
-    CPPUNIT_ASSERT_MESSAGE("Failed to not find ending string", !input.endsWith("lo"));
+    CPPUNIT_ASSERT_MESSAGE("Failed to find ending String", input.endsWith(String("ld")));
+    CPPUNIT_ASSERT_MESSAGE("Failed to not find ending String", !input.endsWith(String("lo")));
+
+    CPPUNIT_ASSERT_MESSAGE("Failed to find ending std::string", input.endsWith(std::string("ld")));
+    CPPUNIT_ASSERT_MESSAGE("Failed to not find ending std::string", !input.endsWith(std::string("lo")));
+
+    CPPUNIT_ASSERT_MESSAGE("Failed to find ending C string", input.endsWith("ld"));
+    CPPUNIT_ASSERT_MESSAGE("Failed to not find ending C string", !input.endsWith("lo"));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -605,6 +653,8 @@ void StringTest::testLastIndexOfString() {
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Returned incorrect index", 5, input.lastIndexOf(String("World")));
     CPPUNIT_ASSERT_EQUAL_MESSAGE("Found String outside of index",
                                  -1, input.lastIndexOf(String("HeKKKKKKKK")));
+
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Returned incorrect index", input.length(), input.lastIndexOf(String()));
 }
 
 ////////////////////////////////////////////////////////////////////////////////

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/2d9ce2f3/activemq-cpp/src/test/decaf/lang/StringTest.h
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/decaf/lang/StringTest.h b/activemq-cpp/src/test/decaf/lang/StringTest.h
index 0c7ec61..e482bf4 100644
--- a/activemq-cpp/src/test/decaf/lang/StringTest.h
+++ b/activemq-cpp/src/test/decaf/lang/StringTest.h
@@ -34,9 +34,11 @@ namespace lang {
         CPPUNIT_TEST( testConstructorCStringSizeOffsetAndLength );
         CPPUNIT_TEST( testConstructorStdString );
         CPPUNIT_TEST( testConstructorString );
+        CPPUNIT_TEST( testConstructorCharFill );
         CPPUNIT_TEST( testAssignmentString );
         CPPUNIT_TEST( testAssignmentStdString );
         CPPUNIT_TEST( testAssignmentCString );
+        CPPUNIT_TEST( testCompact );
         CPPUNIT_TEST( testHashCode );
         CPPUNIT_TEST( testIsEmpty );
         CPPUNIT_TEST( testSubstring1 );
@@ -109,9 +111,11 @@ namespace lang {
         void testConstructorCStringSizeOffsetAndLength();
         void testConstructorStdString();
         void testConstructorString();
+        void testConstructorCharFill();
         void testAssignmentString();
         void testAssignmentStdString();
         void testAssignmentCString();
+        void testCompact();
         void testHashCode();
         void testIsEmpty();
         void testSubstring1();

http://git-wip-us.apache.org/repos/asf/activemq-cpp/blob/2d9ce2f3/activemq-cpp/src/test/testRegistry.cpp
----------------------------------------------------------------------
diff --git a/activemq-cpp/src/test/testRegistry.cpp b/activemq-cpp/src/test/testRegistry.cpp
index 7ec7e1e..e49561e 100644
--- a/activemq-cpp/src/test/testRegistry.cpp
+++ b/activemq-cpp/src/test/testRegistry.cpp
@@ -265,8 +265,8 @@
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::lang::PointerTest );
 //#include <decaf/lang/ArrayPointerTest.h>
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::lang::ArrayPointerTest );
-//#include <decaf/lang/StringTest.h>
-//CPPUNIT_TEST_SUITE_REGISTRATION( decaf::lang::StringTest );
+#include <decaf/lang/StringTest.h>
+CPPUNIT_TEST_SUITE_REGISTRATION( decaf::lang::StringTest );
 //
 //#include <decaf/net/InetAddressTest.h>
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::InetAddressTest );
@@ -282,8 +282,8 @@
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::SocketTest );
 //#include <decaf/net/URITest.h>
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::URITest );
-#include <decaf/net/URLTest.h>
-CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::URLTest );
+//#include <decaf/net/URLTest.h>
+//CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::URLTest );
 //#include <decaf/net/URISyntaxExceptionTest.h>
 //CPPUNIT_TEST_SUITE_REGISTRATION( decaf::net::URISyntaxExceptionTest );
 //#include <decaf/net/URLEncoderTest.h>