www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - logical operands on strings

reply "Erik van Velzen" <erik evanv.nl> writes:
I would like to do this:

     string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
     string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
     string three = one ^ two;


The closests I've been able to get is:

     string three = xor(one, two);

     string xor(string one, string two) {
         int len = min(one.length, two.length);
         string result;
         for(int i=0; i<len; i++) {
             result ~= one[i] ^ two[i];
         }
         return cast(string)result;
     }

Question 1: is there a more elegant way to implement the function 
xor? (foreach-ish or std.algorithm)


Then I tried to add operator overloading:

     string opBinary(string op)(string lhs, string rhs) {
         static if( op == "^" )
             return xor(lhs, rhs);
         else static assert(false, "operator not possible");
     }

But it doesn't invoke this function.

Question 2: how would I implement "^" for strings?
Jan 12 2014
next sibling parent reply "Meta" <jared771 gmail.com> writes:
On Sunday, 12 January 2014 at 18:21:06 UTC, Erik van Velzen wrote:
 I would like to do this:

     string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
     string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
     string three = one ^ two;


 The closests I've been able to get is:

     string three = xor(one, two);

     string xor(string one, string two) {
         int len = min(one.length, two.length);
         string result;
         for(int i=0; i<len; i++) {
             result ~= one[i] ^ two[i];
         }
         return cast(string)result;
     }

 Question 1: is there a more elegant way to implement the 
 function xor? (foreach-ish or std.algorithm)


 Then I tried to add operator overloading:

     string opBinary(string op)(string lhs, string rhs) {
         static if( op == "^" )
             return xor(lhs, rhs);
         else static assert(false, "operator not possible");
     }

 But it doesn't invoke this function.

 Question 2: how would I implement "^" for strings?
It looks like your opBinary on strings is an attempt at globally overriding the XOR operator. I'm almost 100% sure this won't work in D. All operator overloads have to be part of a class or struct.
Jan 12 2014
parent reply "Erik van Velzen" <erik evanv.nl> writes:
On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
 It looks like your opBinary on strings is an attempt at 
 globally overriding the XOR operator. I'm almost 100% sure this 
 won't work in D. All operator overloads have to be part of a 
 class or struct.
How would I do that without rewriting an entire string class? It seems I can't even inherit from string. Forgive me for making the comparison, but I believe in C++ i can simply implement this function and be done with it: string operator^(string lhs, string rhs);
Jan 12 2014
next sibling parent reply "TheFlyingFiddle" <kurtyan student.chalmers.se> writes:
On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen wrote:
 On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
 It looks like your opBinary on strings is an attempt at 
 globally overriding the XOR operator. I'm almost 100% sure 
 this won't work in D. All operator overloads have to be part 
 of a class or struct.
How would I do that without rewriting an entire string class?
Well something like this. struct MyString { string value; alias value this; auto opBinary(string op)(string rhs) if( op == "^" ) { string result; foreach(i; 0 .. min(value.length, rhs.length)) result ~= value[i] ^ rhs[i]; return MyString(result); } } auto mstr(string s) { return MyString(s); } auto s = "Hello"; auto s2 = "World"; auto res = s.mstr ^ s2; or string res = s.mstr ^ s2; //If you want the result to be a string. While this works it's not that much better then the simple: auto s = "Hello"; auto s2 = "World"; auto res = s.xor(s2);
 It seems I can't even inherit from string.
In D a string is not a class its just an immutable array (slice) of char. alias string = immutable(char[]);
Jan 12 2014
parent "Meta" <jared771 gmail.com> writes:
On Sunday, 12 January 2014 at 19:12:13 UTC, TheFlyingFiddle wrote:
 On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen 
 wrote:
 On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
 It looks like your opBinary on strings is an attempt at 
 globally overriding the XOR operator. I'm almost 100% sure 
 this won't work in D. All operator overloads have to be part 
 of a class or struct.
How would I do that without rewriting an entire string class?
Well something like this. struct MyString { string value; alias value this; auto opBinary(string op)(string rhs) if( op == "^" ) { string result; foreach(i; 0 .. min(value.length, rhs.length)) result ~= value[i] ^ rhs[i]; return MyString(result); } } auto mstr(string s) { return MyString(s); } auto s = "Hello"; auto s2 = "World"; auto res = s.mstr ^ s2; or string res = s.mstr ^ s2; //If you want the result to be a string. While this works it's not that much better then the simple: auto s = "Hello"; auto s2 = "World"; auto res = s.xor(s2);
 It seems I can't even inherit from string.
In D a string is not a class its just an immutable array (slice) of char. alias string = immutable(char[]);
You can also use opBinaryRight for when your custom string class is on the right side of the operand, so string ^ MyString also works. This pretty much obviates the need for global operator overloading, at least in this case.
Jan 12 2014
prev sibling next sibling parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 12 January 2014 at 18:37:40 UTC, Erik van Velzen wrote:
 On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
 It looks like your opBinary on strings is an attempt at 
 globally overriding the XOR operator. I'm almost 100% sure 
 this won't work in D. All operator overloads have to be part 
 of a class or struct.
How would I do that without rewriting an entire string class? It seems I can't even inherit from string. Forgive me for making the comparison, but I believe in C++ i can simply implement this function and be done with it: string operator^(string lhs, string rhs);
global operator overloads aren't allowed in D. For your particular problem I would construct a wrapper around string using psuedo-inheritance via 'alias this': struct MyString { string nativeStr; alias nativeStr this; auto opBinary(string op)(string rhs) if(op == "^") { return xor(nativeStr, rhs); } void opOpBinary(string op)(string rhs) if(op == "^") { nativeStr = xor(nativeStr, rhs); } } All normal string operations on a MyString will be applied to nativeStr thanks to alias this, except the ^ and ^= whch are intercepted by the opBinary and opOpBinary methods in MyString. The ^= could be more efficient by working in-place. Also, you should pre-allocate the return string in xor as it's a lot quicker than doing repeated append operations.
Jan 12 2014
prev sibling parent Mike Parker <aldacron gmail.com> writes:
On 1/13/2014 3:37 AM, Erik van Velzen wrote:
 On Sunday, 12 January 2014 at 18:28:38 UTC, Meta wrote:
 It looks like your opBinary on strings is an attempt at globally
 overriding the XOR operator. I'm almost 100% sure this won't work in
 D. All operator overloads have to be part of a class or struct.
How would I do that without rewriting an entire string class? It seems I can't even inherit from string.
In D, string is not a class. It's an alias for an immutable array of char.
Jan 12 2014
prev sibling parent reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
On 01/12/2014 10:21 AM, Erik van Velzen wrote:
 I would like to do this:

      string one = x"315c4eeaa8b5f8aaf9174145bf43e1784b";
      string two = x"c29398f5f3251a0d47e503c66e935de81230b59b7a";
      string three = one ^ two;


 The closests I've been able to get is:

      string three = xor(one, two);

      string xor(string one, string two) {
          int len = min(one.length, two.length);
          string result;
          for(int i=0; i<len; i++) {
              result ~= one[i] ^ two[i];
          }
          return cast(string)result;
      }

 Question 1: is there a more elegant way to implement the function xor?
 (foreach-ish or std.algorithm)


 Then I tried to add operator overloading:

      string opBinary(string op)(string lhs, string rhs) {
          static if( op == "^" )
              return xor(lhs, rhs);
          else static assert(false, "operator not possible");
      }

 But it doesn't invoke this function.

 Question 2: how would I implement "^" for strings?
XOR is not a valid operation on a UTF-8 code unit. ;) It makes more sense to work with ubyte arrays. However, I found two usability issues with it: 1) std.conv.to did not work from string to ubyte[]; so, I wrote a function. 2) Array-wise operations does not support the following syntax auto three = one[] ^ two[]; Otherwise, ^= works with slices: import std.stdio; ubyte[] toBytes(string s) { return cast(ubyte[])s.dup; } void main() { ubyte[] one = x"55".toBytes; ubyte[] two = x"aa".toBytes; ubyte[] three = one.dup; three[] ^= two[]; assert(one == x"55"); assert(two == x"aa"); assert(three == x"ff"); } Ali
Jan 12 2014
parent reply "Meta" <jared771 gmail.com> writes:
On Sunday, 12 January 2014 at 19:22:57 UTC, Ali Çehreli wrote:
 2) Array-wise operations does not support the following syntax

     auto three = one[] ^ two[];
Is this a bug or intended?
Jan 12 2014
parent "John Colvin" <john.loughran.colvin gmail.com> writes:
On Sunday, 12 January 2014 at 19:27:18 UTC, Meta wrote:
 On Sunday, 12 January 2014 at 19:22:57 UTC, Ali Çehreli wrote:
 2) Array-wise operations does not support the following syntax

    auto three = one[] ^ two[];
Is this a bug or intended?
intended. It would require an implicit allocation, which is incongruent with array operations being fast. It's been discussed at length.
Jan 12 2014