private AddressSet xorSets(AddressSetView addrSet) {
		AddressSet newSet = new AddressSet();

		AddressRangeIterator range1It = getAddressRanges();
		AddressRangeIterator range2It = addrSet.getAddressRanges();

		AddressRange range1 = range1It.hasNext() ? range1It.next() : null;
		AddressRange range2 = range2It.hasNext() ? range2It.next() : null;

		while (range1 != null && range2 != null) {
			switch (compareRange(range1, range2)) {
				case RANGE1_COMPLETELY_AFTER_RANGE2:
					// no overlap in range2, add it to tree and get next range2
					newSet.add(range2);
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_COMPLETELY_BEFORE_RANGE2:
					// no overlap in range1, add it to tree and get next range1
					newSet.add(range1);
					range1 = range1It.hasNext() ? range1It.next() : null;
					break;
				case RANGE1_EQUALS_RANGE2:
					// total overlap don't add either one, get next range1 and range2
					range1 = range1It.hasNext() ? range1It.next() : null;
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_AT_RANGE2_ENDS_AFTER_RANGE2:
					// range2 overlaps, truncate range1 and get new range2
					range1 =
						new AddressRangeImpl(range2.getMaxAddress().next(), range1.getMaxAddress());
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_AT_RANGE2_ENDS_BEFORE_RANGE2:
					// range1 overlaps, truncate range2 and get new range1
					range2 =
						new AddressRangeImpl(range1.getMaxAddress().next(), range2.getMaxAddress());
					range1 = range1It.hasNext() ? range1It.next() : null;
					break;
				case RANGE1_STARTS_BEFORE_RANGE2_ENDS_AFTER_RANGE2:
					// add beginning of range1 to tree, truncate range1 to end of range2, get new range2
					newSet.addRange(range1.getMinAddress(), range2.getMinAddress().previous());
					range1 =
						new AddressRangeImpl(range2.getMaxAddress().next(), range1.getMaxAddress());
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_BEFORE_RANGE2_ENDS_AT_RANGE2_END:
					// add beginning of range1 to tree, get new range1 and range2
					newSet.addRange(range1.getMinAddress(), range2.getMinAddress().previous());
					range1 = range1It.hasNext() ? range1It.next() : null;
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_BEFORE_RANGE2_ENDS_INSIDE_RANGE2:
					// add in beginning of range1 to tree, truncate range2 to end of range1, get new range1
					newSet.addRange(range1.getMinAddress(), range2.getMinAddress().previous());
					range2 =
						new AddressRangeImpl(range1.getMaxAddress().next(), range2.getMaxAddress());
					range1 = range1It.hasNext() ? range1It.next() : null;
					break;
				case RANGE1_STARTS_INSIDE_RANGE2_ENDS_AFTER_RANGE2:
					// add in beginning of range2, truncate range1 to end of range2, get new range2
					newSet.addRange(range2.getMinAddress(), range1.getMinAddress().previous());
					range1 =
						new AddressRangeImpl(range2.getMaxAddress().next(), range1.getMaxAddress());
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_INSIDE_RANGE2_ENDS_AT_RANGE2:
					// add beginning of range2 to tree, get new range1 and range2
					newSet.addRange(range2.getMinAddress(), range1.getMinAddress().previous());
					range1 = range1It.hasNext() ? range1It.next() : null;
					range2 = range2It.hasNext() ? range2It.next() : null;
					break;
				case RANGE1_STARTS_INSIDE_RANGE2_ENDS_INSIDE_RANGE2:
					// add beginning of range2 to tree, truncate range2 to end range1, get new range1
					newSet.addRange(range2.getMinAddress(), range1.getMinAddress().previous());
					range2 =
						new AddressRangeImpl(range1.getMaxAddress().next(), range2.getMaxAddress());
					range1 = range1It.hasNext() ? range1It.next() : null;
					break;

			}
		}
		while (range1 != null) {
			newSet.add(range1);
			range1 = range1It.hasNext() ? range1It.next() : null;
		}
		while (range2 != null) {
			newSet.add(range2);
			range2 = range2It.hasNext() ? range2It.next() : null;
		}
		return newSet;
	}
Determines if the optimal algorithm for an operation.  Generally set operations can be done
either by applying each range of the given address set to this set OR by linearly visiting
each range in both this set and the other set.  The first approach involves doing a
binary search in this set for each range in the given set costing Nlog(M) operations where
N is the size of this set and M is the size of the other set.  The second approach involves
visiting every range in both sets in order so the cost is N + M.  Therefor, if N+M is less
than Nlog(M), we should use a linear algorithm.

@param set the other address set to operate against.
@return true if a linear algorithm will likely be faster that a series of binary searches.
Ghidra/Framework/SoftwareModeling/src/main/java/ghidra/program/model/address/AddressSet.java