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 <[email protected]> Authored: Thu Nov 7 17:06:37 2013 -0500 Committer: Timothy Bish <[email protected]> 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>
