Difference between revisions of "Using Data"

From reSIProcate
Jump to: navigation, search
(Creating from Another Type)
(convert another page with sample code to display it in syntax-highlighted form)
 
Line 24: Line 24:
 
This is probably a good place to discuss stack based Data buffers and DataStream use.
 
This is probably a good place to discuss stack based Data buffers and DataStream use.
  
 +
<syntaxhighlight lang="cpp">
 
  void reserve(size_type capacity);
 
  void reserve(size_type capacity);
 +
</syntaxhighlight>
  
 
=Creating a Data=
 
=Creating a Data=
Line 34: Line 36:
  
 
Conversion from null-terminated c-style string:
 
Conversion from null-terminated c-style string:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
char *mySignedCharPtr = "Hello";
 
char *mySignedCharPtr = "Hello";
 
resip::Data data1(mySignedCharPtr); // data1 contains "Hello"
 
resip::Data data1(mySignedCharPtr); // data1 contains "Hello"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from null-terminated c-style string of unsigned characters (for the criminally insane):
 
Conversion from null-terminated c-style string of unsigned characters (for the criminally insane):
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
unsigned char *myUnsignedCharPtr = "Hej";
 
unsigned char *myUnsignedCharPtr = "Hej";
 
resip::Data data2(myUnsignedCharPtr); // data2 contains "Hej"
 
resip::Data data2(myUnsignedCharPtr); // data2 contains "Hej"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from STL string:
 
Conversion from STL string:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
std::string myString = "Hola";
 
std::string myString = "Hola";
 
resip::Data data3(myString); // data3 contains "Hola"
 
resip::Data data3(myString); // data3 contains "Hola"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from integer:
 
Conversion from integer:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
int myInt = -75;
 
int myInt = -75;
 
resip::Data data4(myInt); // data4 contains "-75"
 
resip::Data data4(myInt); // data4 contains "-75"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from unsigned long integer:
 
Conversion from unsigned long integer:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
unsigned long myUnsignedLong = 12345;
 
unsigned long myUnsignedLong = 12345;
 
resip::Data data5(myUnsignedLong); // data5 contains "12345"
 
resip::Data data5(myUnsignedLong); // data5 contains "12345"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from unsigned integer:
 
Conversion from unsigned integer:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
unsigned int myUnsignedInt = 75;
 
unsigned int myUnsignedInt = 75;
 
resip::Data data6(myUnsignedInt); // data6 contains "75"
 
resip::Data data6(myUnsignedInt); // data6 contains "75"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from double takes an optional precision parameter which indicates the number of digits after the decimal point. Trailing zeros are omitted. If not specified, the default precision is 4.
 
Conversion from double takes an optional precision parameter which indicates the number of digits after the decimal point. Trailing zeros are omitted. If not specified, the default precision is 4.
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
double myDouble = 7.12345;
 
double myDouble = 7.12345;
 
resip::Data data7(myDouble); // data7 contains "7.1234"
 
resip::Data data7(myDouble); // data7 contains "7.1234"
 
resip::Data data8(myDouble, resip::Data::TwoDigitPrecision); // data8 contains "7.12"
 
resip::Data data8(myDouble, resip::Data::TwoDigitPrecision); // data8 contains "7.12"
 
resip::Data data9(myDouble, resip::Data::SixDigitPrecision); // data9 contains "7.12345"
 
resip::Data data9(myDouble, resip::Data::SixDigitPrecision); // data9 contains "7.12345"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from boolean:
 
Conversion from boolean:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
bool myBool = true;
 
bool myBool = true;
 
resip::Data data10(myBool); // data10 contains "true"
 
resip::Data data10(myBool); // data10 contains "true"
</nowiki></pre>
+
</syntaxhighlight>
  
 
Conversion from character:
 
Conversion from character:
<pre><nowiki>
+
<syntaxhighlight lang="cpp">
 
char myChar = 'a';
 
char myChar = 'a';
 
resip::Data data11(myChar); // data11 contains "a"
 
resip::Data data11(myChar); // data11 contains "a"
</nowiki></pre>
+
</syntaxhighlight>
  
 
If none of the preceding methods give you the tools that you need to convert from another data type, you can use the "Data::from" class method to create the Data you want. The only requirement is that the type that you're creating the Data from has an associated streaming operator. This is particularly useful if you want to create a Data from a non-primitive data type.
 
If none of the preceding methods give you the tools that you need to convert from another data type, you can use the "Data::from" class method to create the Data you want. The only requirement is that the type that you're creating the Data from has an associated streaming operator. This is particularly useful if you want to create a Data from a non-primitive data type.
  
 +
<syntaxhighlight lang="cpp">
 
  ComplexDataThingy foo;
 
  ComplexDataThingy foo;
 
  resip::Data data12 = Data::from(foo);
 
  resip::Data data12 = Data::from(foo);
 +
</syntaxhighlight>
  
 
==Creating from an Existing Buffer==
 
==Creating from an Existing Buffer==
Line 98: Line 102:
 
The easiest way to create a Data from an existing buffer is to pass in a buffer and the number of bytes of meaningful data that exist in the buffer. This constructor operates in "Take" mode -- the Data will copy the passed-in buffer immediately.
 
The easiest way to create a Data from an existing buffer is to pass in a buffer and the number of bytes of meaningful data that exist in the buffer. This constructor operates in "Take" mode -- the Data will copy the passed-in buffer immediately.
  
 +
<syntaxhighlight lang="cpp">
 
  char buffer[2048];
 
  char buffer[2048];
 
  int bytes = read(fd, buffer, sizeof(buffer));
 
  int bytes = read(fd, buffer, sizeof(buffer));
 
  resip::Data myData(buffer, bytes);
 
  resip::Data myData(buffer, bytes);
 +
</syntaxhighlight>
  
 
Alternately, you can explicitly indicate the sharing mode desired; once again, the length indictated is the number of meaninful bytes already present in the buffer, not the total length of the buffer. No constructor yet exists which allows you to indicate both the number of meaningful bytes and the total length of the buffer; if you have a need for such a constructor, though, it should be easy to add one. (ed. allocate the desired size buffer and append the bytes you want)
 
Alternately, you can explicitly indicate the sharing mode desired; once again, the length indictated is the number of meaninful bytes already present in the buffer, not the total length of the buffer. No constructor yet exists which allows you to indicate both the number of meaningful bytes and the total length of the buffer; if you have a need for such a constructor, though, it should be easy to add one. (ed. allocate the desired size buffer and append the bytes you want)
  
 +
<syntaxhighlight lang="cpp">
 
  char buffer[2048];
 
  char buffer[2048];
 
  int bytes = read(fd, buffer, sizeof(buffer));
 
  int bytes = read(fd, buffer, sizeof(buffer));
 
  resip::Data myData(resip::Data::Borrow, buffer, bytes);
 
  resip::Data myData(resip::Data::Borrow, buffer, bytes);
 +
</syntaxhighlight>
  
 
If you are creating a Data from a c-style null-terminated string, you are given the option of indicating a sharing mode also. Be very, very careful that your c-style string ''is'' null terminated if you use this constructor.
 
If you are creating a Data from a c-style null-terminated string, you are given the option of indicating a sharing mode also. Be very, very careful that your c-style string ''is'' null terminated if you use this constructor.
  
 +
<syntaxhighlight lang="cpp">
 
  char myChar[] = "Hello";
 
  char myChar[] = "Hello";
 
  resip::Data myData(resip::Data::Borrow, myChar);
 
  resip::Data myData(resip::Data::Borrow, myChar);
 +
</syntaxhighlight>
  
 
Finally, you can create a Data from another Data with an explicit allocation type. This is kind of copy-contstructor-ish, except that the compiler won't call it for you:
 
Finally, you can create a Data from another Data with an explicit allocation type. This is kind of copy-contstructor-ish, except that the compiler won't call it for you:
  
 +
<syntaxhighlight lang="cpp">
 
  resip::Data* myData = new resip::Data("I'm a teapot");
 
  resip::Data* myData = new resip::Data("I'm a teapot");
 
  resip::Data* myOtherData = new resip::Data(resip::Data::Share, *myData);
 
  resip::Data* myOtherData = new resip::Data(resip::Data::Share, *myData);
 +
</syntaxhighlight>
  
 
=Data Comparisons=
 
=Data Comparisons=
Line 122: Line 134:
 
This section is not yet finished.
 
This section is not yet finished.
  
 +
<syntaxhighlight lang="cpp">
 
  bool operator==(const Data& rhs) const;
 
  bool operator==(const Data& rhs) const;
 
  bool operator==(const char* rhs) const;
 
  bool operator==(const char* rhs) const;
Line 134: Line 147:
 
  bool operator>(const char* rhs) const;
 
  bool operator>(const char* rhs) const;
 
  bool operator>=(const char* rhs) const;
 
  bool operator>=(const char* rhs) const;
 +
</syntaxhighlight>
  
 
Returns true iff the argument Data is a prefix (begining) of this Data. For example: <code>assert(Data("abracadabra").prefix("abrac"));</code>
 
Returns true iff the argument Data is a prefix (begining) of this Data. For example: <code>assert(Data("abracadabra").prefix("abrac"));</code>
  
 +
<syntaxhighlight lang="cpp">
 
  bool prefix(const Data& pre) const;
 
  bool prefix(const Data& pre) const;
 +
</syntaxhighlight>
  
 
Returns true iff the argument Data is a postfix (end) of this Data. For example: <code>assert(Data("abracadabra").postfix("dabra"));</code>
 
Returns true iff the argument Data is a postfix (end) of this Data. For example: <code>assert(Data("abracadabra").postfix("dabra"));</code>
  
 +
<syntaxhighlight lang="cpp">
 
  bool postfix(const Data& post) const;
 
  bool postfix(const Data& post) const;
 +
</syntaxhighlight>
  
 
<code>Data::Empty</code> is a static constant that is a Data with no bytes. It is immutable and of length zero.
 
<code>Data::Empty</code> is a static constant that is a Data with no bytes. It is immutable and of length zero.
Line 148: Line 166:
 
This section is not yet completed
 
This section is not yet completed
  
 +
<syntaxhighlight lang="cpp">
 
  Data substr(size_type first, size_type count = Data::npos) const;
 
  Data substr(size_type first, size_type count = Data::npos) const;
 
  Data operator+(const Data& rhs) const;
 
  Data operator+(const Data& rhs) const;
Line 161: Line 180:
 
  void clear();
 
  void clear();
 
  int replace(const Data& match, const Data& target);
 
  int replace(const Data& match, const Data& target);
 +
</syntaxhighlight>
  
 
=Data Transformations=
 
=Data Transformations=
 
This section is not yet completed
 
This section is not yet completed
  
 +
<syntaxhighlight lang="cpp">
 
  Data md5() const;
 
  Data md5() const;
 
  Data& lowercase();
 
  Data& lowercase();
Line 186: Line 207:
 
     escapeToStream(std::ostream& str,
 
     escapeToStream(std::ostream& str,
 
                     Predicate shouldEscape) const;
 
                     Predicate shouldEscape) const;
 +
</syntaxhighlight>
  
 
=Data Conversion=
 
=Data Conversion=
Line 192: Line 214:
 
This section is not yet finished
 
This section is not yet finished
  
 +
<syntaxhighlight lang="cpp">
 
  Data& operator=(const char* str);
 
  Data& operator=(const char* str);
 +
</syntaxhighlight>
  
 
Converts from any type T that supports the insertion operator<< to Data. This construct is used chiefly for debugging. Conversions like this can usually be handled more efficiently with direct use of DataStream.
 
Converts from any type T that supports the insertion operator<< to Data. This construct is used chiefly for debugging. Conversions like this can usually be handled more efficiently with direct use of DataStream.
  
 +
<syntaxhighlight lang="cpp">
 
  class <T>
 
  class <T>
 
  static Data from(const T& x);
 
  static Data from(const T& x);
 +
</syntaxhighlight>
  
 
==Converting to Other Types==
 
==Converting to Other Types==
 
This section is not yet completed
 
This section is not yet completed
  
 +
<syntaxhighlight lang="cpp">
 
  int convertInt() const;
 
  int convertInt() const;
  
Line 209: Line 236:
  
 
  UInt64 convertUInt64() const;
 
  UInt64 convertUInt64() const;
 +
</syntaxhighlight>
  
 
=Examining the Data=
 
=Examining the Data=
 
This section is not yet completed
 
This section is not yet completed
  
 +
<syntaxhighlight lang="cpp">
 
  char& operator[](size_type p);
 
  char& operator[](size_type p);
 
  char operator[](size_type p) const;
 
  char operator[](size_type p) const;
Line 225: Line 254:
 
  size_type find(const Data& match, size_type start = 0) const;
 
  size_type find(const Data& match, size_type start = 0) const;
 
  size_type find(const char* match, size_type start = 0) const;
 
  size_type find(const char* match, size_type start = 0) const;
 +
</syntaxhighlight>
  
 
=Static Convenience Methods=
 
=Static Convenience Methods=
 
These methods are used by Data to generate hash values for use in hash tables. The methods are publically available to aid the creation of custom hashes on other types with contiguous bytes. There are slightly faster hash functions, but these are quite fast, have provable good distribution properties, and can be varied for security purposes.
 
These methods are used by Data to generate hash values for use in hash tables. The methods are publically available to aid the creation of custom hashes on other types with contiguous bytes. There are slightly faster hash functions, but these are quite fast, have provable good distribution properties, and can be varied for security purposes.
  
 +
<syntaxhighlight lang="cpp">
 
  static size_t rawHash(const char* c, size_t size);
 
  static size_t rawHash(const char* c, size_t size);
 
  static size_t rawCaseInsensitiveHash(const char* c, size_t size);
 
  static size_t rawCaseInsensitiveHash(const char* c, size_t size);
 +
</syntaxhighlight>

Latest revision as of 20:56, 26 April 2011

The Data class encapsulates a buffer of bytes. It is similar in functionality to many common string classes, except that it operates on collections of bytes instead of collections of characters. In particular, Data is meant to operate on buffers that may or may not contain binary data. That said, there are a number of operations on Data which are written with manipulation of text in mind, and many methods go out of their way to ensure that the buffer is often null-terminated. It's a bit schizophrenic that way. (ed.: the null termination is useful when rooting about in the debugger).

Buffer Management[edit]

Management Models[edit]

At any given time, a Data is associated with a single buffer which contains the bytes inside the Data. This buffer may be owned by the Data object itself, or owned by an external party. Additionally, data owned by an external party can be considered changeable or unchangeable.

Sharing StyleBuffer OwnershipBuffer Mutable?
ShareExternal to Data classNo
BorrowExternal to Data classYes
TakeOwned by Data classYes

If a Data containing an immutable buffer (i.e. Sharing Mode is Share) is changed, then a new buffer is allocated by the Data, the contents of the existing (immutable) buffer are copied into it, and the modification is performed on the new buffer. This newly allocated buffer is owned by the Data.

If a modification is performed on a Data which requires more space than is available in the underlying buffer, then a larger buffer is allocated, the existing bytes are copied into the new buffer, and the modification is performed on the new buffer. If the old buffer was owned by the Data, it will be deallocated.

Note that all deallocation performed by the Data uses delete[]; consequently, any data owned by the Data (e.g. Sharing Mode is Take) must be allocated from the normal heap using new[], lest you anger the portability gods.

Finally, users of Data should note that a Data created from a buffer with Share or Borrow sharing must not outlive the buffer itself.

Foo[edit]

This section isn't even finished enough to have a proper name. This is probably a good place to discuss stack based Data buffers and DataStream use.

 void reserve(size_type capacity);

Creating a Data[edit]

Data conveniently has fifteen non-deprecated constructors for your creation pleasure. The default constructor will ultimately cause the Data to allocate its own internal memory. The copy constuctor does pretty much what you expect it to do.

Creating from Another Type[edit]

Data will take a variety of different kinds of types in its constructor and convert them into the string representation of those types.

Conversion from null-terminated c-style string:

char *mySignedCharPtr = "Hello";
resip::Data data1(mySignedCharPtr); // data1 contains "Hello"

Conversion from null-terminated c-style string of unsigned characters (for the criminally insane):

unsigned char *myUnsignedCharPtr = "Hej";
resip::Data data2(myUnsignedCharPtr); // data2 contains "Hej"

Conversion from STL string:

std::string myString = "Hola";
resip::Data data3(myString); // data3 contains "Hola"

Conversion from integer:

int myInt = -75;
resip::Data data4(myInt); // data4 contains "-75"

Conversion from unsigned long integer:

unsigned long myUnsignedLong = 12345;
resip::Data data5(myUnsignedLong); // data5 contains "12345"

Conversion from unsigned integer:

unsigned int myUnsignedInt = 75;
resip::Data data6(myUnsignedInt); // data6 contains "75"

Conversion from double takes an optional precision parameter which indicates the number of digits after the decimal point. Trailing zeros are omitted. If not specified, the default precision is 4.

double myDouble = 7.12345;
resip::Data data7(myDouble); // data7 contains "7.1234"
resip::Data data8(myDouble, resip::Data::TwoDigitPrecision); // data8 contains "7.12"
resip::Data data9(myDouble, resip::Data::SixDigitPrecision); // data9 contains "7.12345"

Conversion from boolean:

bool myBool = true;
resip::Data data10(myBool); // data10 contains "true"

Conversion from character:

char myChar = 'a';
resip::Data data11(myChar); // data11 contains "a"

If none of the preceding methods give you the tools that you need to convert from another data type, you can use the "Data::from" class method to create the Data you want. The only requirement is that the type that you're creating the Data from has an associated streaming operator. This is particularly useful if you want to create a Data from a non-primitive data type.

 ComplexDataThingy foo;
 resip::Data data12 = Data::from(foo);

Creating from an Existing Buffer[edit]

The easiest way to create a Data from an existing buffer is to pass in a buffer and the number of bytes of meaningful data that exist in the buffer. This constructor operates in "Take" mode -- the Data will copy the passed-in buffer immediately.

 char buffer[2048];
 int bytes = read(fd, buffer, sizeof(buffer));
 resip::Data myData(buffer, bytes);

Alternately, you can explicitly indicate the sharing mode desired; once again, the length indictated is the number of meaninful bytes already present in the buffer, not the total length of the buffer. No constructor yet exists which allows you to indicate both the number of meaningful bytes and the total length of the buffer; if you have a need for such a constructor, though, it should be easy to add one. (ed. allocate the desired size buffer and append the bytes you want)

 char buffer[2048];
 int bytes = read(fd, buffer, sizeof(buffer));
 resip::Data myData(resip::Data::Borrow, buffer, bytes);

If you are creating a Data from a c-style null-terminated string, you are given the option of indicating a sharing mode also. Be very, very careful that your c-style string is null terminated if you use this constructor.

 char myChar[] = "Hello";
 resip::Data myData(resip::Data::Borrow, myChar);

Finally, you can create a Data from another Data with an explicit allocation type. This is kind of copy-contstructor-ish, except that the compiler won't call it for you:

 resip::Data* myData = new resip::Data("I'm a teapot");
 resip::Data* myOtherData = new resip::Data(resip::Data::Share, *myData);

Data Comparisons[edit]

This section is not yet finished.

 bool operator==(const Data& rhs) const;
 bool operator==(const char* rhs) const;
 bool operator!=(const Data& rhs) const;
 bool operator!=(const char* rhs) const;
 bool operator<(const Data& rhs) const;
 bool operator<=(const Data& rhs) const;
 bool operator<(const char* rhs) const;
 bool operator<=(const char* rhs) const;
 bool operator>(const Data& rhs) const;
 bool operator>=(const Data& rhs) const;
 bool operator>(const char* rhs) const;
 bool operator>=(const char* rhs) const;

Returns true iff the argument Data is a prefix (begining) of this Data. For example: assert(Data("abracadabra").prefix("abrac"));

 bool prefix(const Data& pre) const;

Returns true iff the argument Data is a postfix (end) of this Data. For example: assert(Data("abracadabra").postfix("dabra"));

 bool postfix(const Data& post) const;

Data::Empty is a static constant that is a Data with no bytes. It is immutable and of length zero.

Data Manipulations[edit]

This section is not yet completed

 Data substr(size_type first, size_type count = Data::npos) const;
 Data operator+(const Data& rhs) const;
 Data operator+(const char* str) const;
 Data operator+(char c) const;
 Data& operator+=(const Data& rhs);
 Data& operator+=(const char* str);
 Data& operator+=(char c);
 Data& operator^=(const Data& rhs);
 Data& append(const char* str, size_type len);
 size_type truncate(size_t len);
 Data trunc(size_type trunc) const;
 void clear();
 int replace(const Data& match, const Data& target);

Data Transformations[edit]

This section is not yet completed

 Data md5() const;
 Data& lowercase();
 Data& uppercase();
 Data hex() const;
 Data escaped() const;
 Data charEncoded() const;
 Data charUnencoded() const;
 Data urlEncoded() const;
 Data urlDecoded() const;
 std::ostream& urlEncode(std::ostream& s)
 std::ostream& urlDecode(std::ostream& s)
 Data base64decode() const;
 Data base64encode(bool useUrlSafe=false) const;

 size_t hash() const;

 size_t caseInsensitivehash() const;

 template<class Predicate> std::ostream&
     escapeToStream(std::ostream& str,
                    Predicate shouldEscape) const;

Data Conversion[edit]

Converting from Other Types[edit]

This section is not yet finished

 Data& operator=(const char* str);

Converts from any type T that supports the insertion operator<< to Data. This construct is used chiefly for debugging. Conversions like this can usually be handled more efficiently with direct use of DataStream.

 class <T>
 static Data from(const T& x);

Converting to Other Types[edit]

This section is not yet completed

 int convertInt() const;

 size_t convertSize() const;

 double convertDouble() const;

 UInt64 convertUInt64() const;

Examining the Data[edit]

This section is not yet completed

 char& operator[](size_type p);
 char operator[](size_type p) const;
 char& at(size_type p);
 bool empty() const { return mSize == 0; }
 size_type size() const { return mSize; } 
 const char* data() const;
 const char* c_str() const;
 const char* begin() const;
 const char* end() const;

 size_type find(const Data& match, size_type start = 0) const;
 size_type find(const char* match, size_type start = 0) const;

Static Convenience Methods[edit]

These methods are used by Data to generate hash values for use in hash tables. The methods are publically available to aid the creation of custom hashes on other types with contiguous bytes. There are slightly faster hash functions, but these are quite fast, have provable good distribution properties, and can be varied for security purposes.

 static size_t rawHash(const char* c, size_t size);
 static size_t rawCaseInsensitiveHash(const char* c, size_t size);