A DottedDecimal Object

Ok, so there are a lot of objects that are represented in dotted decimal notation.  The most common are versions and IP addresses.

Version 3.1.9.27

IP Address: 192.168.0.1

I have to wonder why I have never found in the Standard C++ Library, or in the C# libraries an object for these?  Are they there and I just don’t know how to find them.  It seems they are always just treated as Strings and this makes no sense to me.  Also these seem common enough that they should be standard objects in all languages.

Which IP Address is greater?

192.168.0.2
192.168.0.100

Well, since these are usually treated as strings, then .2 is greater than .100.  Unfortunately that is not correct.  We all know that .100 is greater.

So I created some objects that overload the >,>=,<=,<,==,!= functions.  Maybe these are completely finished, but hey, they are a start. I created C# and C++ versions.  The C# is first, scroll down if you are looking for C++ versions. This is really great for versions that can be different.  However, I think that for an IP address object, that because it is limited to three characters and each section is one byte and only can be seen as 0-255, that a very efficient object could be created, but for now, a more generic DottedDecimal object is fine, though if you had a large list of IP addresses, you may want that efficiency. Also, this is only tested with digits 0-9, not hex, so there is plenty more work to do, but usually version are just 0-9, though sometimes people throw in an "a" or "b" build such as 1.0.0.1a.  That is not handled yet.  So again, much more work to do.  But for my needs these are more than enough for now. If there are already objects like this that are awesome, efficient, tested, and free, let me know.

C# DottedDecimal object for IP address and Versions

For C#, I implement a lot of interfaces too as you can see in the object.

DottedDecimal.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace DottedDecimalProject
{
    public class DottedDecimal
        : IComparable, IComparable<dottedDecimal>, IComparable<string>, ICloneable, IEquatable<string>, IEquatable<dottedDecimal>
    {
        #region Member Variables
        List<long> _DecimalValues;
        CompareDirection _CompareDirection = CompareDirection.LeftToRight;
        #endregion

        #region Constructors
        /*
         * The default constuctor.
         * The default compare direction is left to right
         * No values are added by default.
         */
        public DottedDecimal()
        {
        }

        /*
         * This constructor takes a string in this regex format
         * [0-9]+(\.[0-9])*
         */
        public DottedDecimal(String inDottedDecimalString)
        {
            _DecimalValues = null;
            _DecimalValues = StringToDottedDecimalList(inDottedDecimalString);
        }

        /*
         * This constructor takes two parameters.
         * Parameter 1 is a string in this regex format: [0-9]+(\.[0-9])*
         * Parameter 2 sets the compare direction. See this.Direction.
         */
        public DottedDecimal(String inDottedDecimalString, CompareDirection inCompareDirection)
        {
            _CompareDirection = inCompareDirection;
            _DecimalValues = null;
            _DecimalValues = StringToDottedDecimalList(inDottedDecimalString);
        }
        #endregion

        #region Properties
        /*
         * Returns the dotted decimal object in string format.
         */
        public String DottedDecimalString
        {
            get { return DottedDecimalListToString(); }
            set { _DecimalValues = StringToDottedDecimalList(value); }
        }

        /*
         * The decimal values are stored in order.  If LeftToRight, the left
         * most value is first.  If RightToLeft, the right most value is first.
         */
        public List<long> DecimalValues
        {
            get { return _DecimalValues; }
            set { _DecimalValues = value; }
        }

        /*
         * Determines whether to compare left to right or right to left.
         *
         * LeftToRight - 1.0.0.1 is greater than 1.0.0.0
         *               1.0.10 is greater than 1.0.0.27
         *
         * RightToLeft - 1.0.0.1 is less than 1.0.0.0
         *             - 1.0.10 is less than 1.0.0.27
         */
        public CompareDirection Direction
        {
            get { return _CompareDirection; }
            set
            {
                if (!(this.Direction == value))
                {
                    this._DecimalValues.Reverse();
                }
                _CompareDirection = value;
            }
        }
        #endregion

        #region Functions
        /*
         * Verifies that the CompareDirection values match between two DottedDecimal objects.
         */
        private static bool CompareDirectionsMatch(DottedDecimal left, DottedDecimal right)
        {
            if (left.Direction == right.Direction)
                return true;
            else
                return false;
        }

        /*
         * Overloads the greater than operator (>) to allow for a syntax as follows:
         *
         *      bool b = dd1 > dd2;
         */
        public static bool operator >(DottedDecimal left, DottedDecimal right)
        {
            int count = (left.DecimalValues.Count > right.DecimalValues.Count) ? right.DecimalValues.Count : left.DecimalValues.Count;

            for (int i = 0; i < count; i++)
            {
                // If left side is greater then true;
                if (left.DecimalValues&#91;i&#93; > right.DecimalValues[i])
                {
                    return true;
                }
                // If right side is greater then false;
                if (left.DecimalValues[i] < right.DecimalValues&#91;i&#93;)
                {
                    return false;
                }
                // If it is equal, check the next decimal values over
                if (left.DecimalValues&#91;i&#93; == right.DecimalValues&#91;i&#93;)
                {
                    continue;
                }
            }

            if (left.DecimalValues.Count > right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then has more values, true.
                return true;
            }

            if (left.DecimalValues.Count < right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then the right side has more values, false.
                return false;
            }
            // If we get here both sides are equals, so false
            return false;
        }

        /*
         * Overloads the less than operator (<) to allow for a syntax as follows:
         *
         *      bool b = dd1 < dd2;
         */
        public static bool operator <(DottedDecimal left, DottedDecimal right)
        {
            int count = (left.DecimalValues.Count > right.DecimalValues.Count) ? right.DecimalValues.Count : left.DecimalValues.Count;
            for (int i = 0; i < count; i++)
            {
                // If right side is greater then true;
                if (left.DecimalValues&#91;i&#93; < right.DecimalValues&#91;i&#93;)
                {
                    return true;
                }
                // If the left is greater then false;
                if (left.DecimalValues&#91;i&#93; > right.DecimalValues[i])
                {
                    return false;
                }
                // If it is equal, check the next decimal values over
                if (left.DecimalValues[i] == right.DecimalValues[i])
                {
                    continue;
                }
            }

            if (left.DecimalValues.Count > right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then has more values, false.
                return false;
            }

            if (left.DecimalValues.Count < right.DecimalValues.Count)
            {
                // If the left side has the same values as the right,
                // but then the right side has more values, true.
                return true;
            }
            // If we get here both sides are equals, so false
            return false;
        }

        /*
         * Overloads the equals operator (==) to allow for a syntax as follows:
         *
         *      bool b = dd1 == dd2;
         */
        public static bool operator ==(DottedDecimal left, DottedDecimal right)
        {
            // If there are more values in either side, they aren't equal
            if (!(left.DecimalValues.Count == right.DecimalValues.Count))
            {
                return false;
            }
            for (int i = 0; i < left.DecimalValues.Count; i++)
            {
                // If any one value is not equal, then false
                if (left.DecimalValues&#91;i&#93; != right.DecimalValues&#91;i&#93;)
                {
                    return false;
                }
            }
            // If you get here they are all equal so true
            return true;
        }

        /*
         * Overloads the not equals operator (!=) to allow for a syntax as follows:
         *
         *      bool b = dd1 != dd2;
         */
        public static bool operator !=(DottedDecimal left, DottedDecimal right)
        {
            // If there are more values in either side, they aren't equal
            if (!(left.DecimalValues.Count == right.DecimalValues.Count))
            {
                return true;
            }
            for (int i = 0; i < left.DecimalValues.Count; i++)
            {
                // If any one value is not equal, then true
                if (left.DecimalValues&#91;i&#93; != right.DecimalValues&#91;i&#93;)
                {
                    return true;
                }
            }
            // If you get here they are all equal so false
            return false;
        }

        public override bool Equals(object obj)
        {
            return base.Equals(obj);
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public override string ToString()
        {
            return DottedDecimalString;
        }

        /*
         * Appends a new string value to the left side of a DottedDecimal object.  Adding "12" to
         * 1.0.0 makes it 1.0.0.12.  Because it is a string, you can also add multiple values at
         * a time so adding the string "12.24" makes 1.0.0.12.24.
         */
        void AddToLeftSide(String inVal)
        {
            foreach (string decimalString in inVal.Split('.'))
            {
                _DecimalValues.Insert(0, Convert.ToInt64(inVal));
            }
        }

        /*
         * Appends a new value to the left side of a DottedDecimal object.  Adding 12 to
         * 1.0.0 makes it 1.0.0.12
         */
        public void AddToLeftSide(long inVal)
        {
            _DecimalValues.Insert(0, inVal);
        }

        /*
         * Appends a new string value to the right side of a DottedDecimal object.  Adding "12" to
         * 1.0.0 makes it 12.1.0.0.  Because it is a string, you can also add multiple values at
         * a time so adding the string "12.24" makes 12.24.1.0.0.
         */
        public void AddToRightSide(String inVal)
        {
            foreach (string decimalString in inVal.Split('.'))
            {
                _DecimalValues.Add(Convert.ToInt64(decimalString));
            }
        }

        /*
         * Appends a new value to the right side of a DottedDecimal object.  Adding 12 to
         * 1.0.0 makes it 12.1.0.0
         */
        public void AddToRightSide(long inVal)
        {
            _DecimalValues.Add(inVal);
        }

        private string DottedDecimalListToString()
        {
            string retVal = "";
            if (this.Direction == CompareDirection.LeftToRight)
            {
                foreach (long l in _DecimalValues)
                {
                    if (!retVal.Equals(""))
                    {
                        retVal += ".";
                    }
                    retVal += l;
                }
            }
            else
            {
                for (int i = _DecimalValues.Count - 1; i >= 0; i--)
                {
                    if (!retVal.Equals(""))
                    {
                        retVal += ".";
                    }
                    retVal += _DecimalValues[i];
                }
            }
            return retVal;
        }

        private List<long> StringToDottedDecimalList(String inString)
        {
            List<long> retList = new List<long>();
            foreach (string decimalString in inString.Split('.'))
            {
                retList.Add(Convert.ToInt64(decimalString));
            }
            if (this.Direction == CompareDirection.RightToLeft)
            {
                retList.Reverse();
            }
            return retList;
        }

        #endregion

        #region Interface Functions

        #region IComparable Members
        public int CompareTo(object inOjbect)
        {
            DottedDecimal dd = (DottedDecimal)inOjbect;
            return CompareTo(dd);
        }
        #endregion

        #region IComparable<dottedDecimal> Members
        public int CompareTo(DottedDecimal inDottedDecimal)
        {
            if (this < inDottedDecimal)
                return -1;
            if (this == inDottedDecimal)
                return 0;
            if (this > inDottedDecimal)
                return 1;
            return -2; // Should never get here.
        }
        #endregion

        #region IComparable<string> Members
        public int CompareTo(string inString)
        {
            DottedDecimal dd = new DottedDecimal(inString);
            return CompareTo(dd);
        }
        #endregion

        #region ICloneable Members
        public object Clone()
        {
            return new DottedDecimal(this.DottedDecimalString, this.Direction);
        }

        #endregion

        #region IEquatable<string> Members
        public bool Equals(string inString)
        {
            DottedDecimal dd = new DottedDecimal(inString);
            return this == dd;
        }

        #endregion
        #region IEquatable<dottedDecimal> Members
        public bool Equals(DottedDecimal inDottedDecimal)
        {
            return this == inDottedDecimal;
        }
        #endregion

        #endregion

        #region Enums
        public enum CompareDirection
        {
            LeftToRight,
            RightToLeft
        }
        #endregion
    }
}

C++ DottedDecimal object for IP address and Versions

I tried to overload the common operators, if there is one you would like overloaded, let me know.

DottedDecimal.h

#pragma once
#include <vector>
#include <iostream>
#include "windows.h"

using namespace std;

class DottedDecimal
{
public:
	// Constructors
	DottedDecimal(); // Default constructor
	DottedDecimal(DottedDecimal & inDottedDecimal); // Copy constructor
	DottedDecimal(string inString);
	DottedDecimal(char * inString);
	DottedDecimal(LPTSTR inString);

	// Destructors
	~DottedDecimal();

	// Public functions
	string GetDottedDecimal();

	template <class T>
	void SetDottedDecimal(const T& t);

	vector<long> GetDecimals();

	// Functions Overloading Operators
	friend ostream &operator<<(ostream & dataStream, DottedDecimal & dd);

	friend bool operator==(DottedDecimal & left, DottedDecimal & right);
	friend bool operator!=(DottedDecimal & left, DottedDecimal & right);

	friend bool operator>(DottedDecimal & left, DottedDecimal & right);
	friend bool operator>=(DottedDecimal & left, DottedDecimal & right);

	friend bool operator<(DottedDecimal & left, DottedDecimal & right);
	friend bool operator<=(DottedDecimal & left, DottedDecimal & right);

private:
	// Member Variables
	vector<long> _decimals;

	// Private Functions
	void StringSplit(string inString, string inDelim, vector<string> * outResults);

	template <class T>
	string AnyTypeToString(const T& t);

	template <class T>
	void StringToAnyType(T& t, std::string inString);
};

DottedDecimal.cpp

#include "StdAfx.h"
#include "DottedDecimal.h"
#include <iostream>
#include <sstream>

using namespace std;

DottedDecimal::DottedDecimal()
{
}

DottedDecimal::DottedDecimal(DottedDecimal & inDottedDecimal)
{
	SetDottedDecimal(inDottedDecimal.GetDottedDecimal());
}

DottedDecimal::DottedDecimal(string inString)
{
	SetDottedDecimal(inString);
}

DottedDecimal::DottedDecimal(LPTSTR inString)
{
	wstring ws = wstring(inString);
	string s;
	s.assign(ws.begin(), ws.end());
	SetDottedDecimal(s);
}

DottedDecimal::DottedDecimal(char * inString)
{
	SetDottedDecimal(inString);
}

DottedDecimal::~DottedDecimal()
{
}

string DottedDecimal::GetDottedDecimal()
{
	string retVal = "";
	for (unsigned short i = 0; i < _decimals.size(); i++)
	{
		if (retVal.compare("") != 0)
		{
			retVal += ".";
		}
		retVal += AnyTypeToString(_decimals.at(i));
	}
	return retVal;
}

template <class T>
void DottedDecimal::SetDottedDecimal(const T& t)
{
	_decimals.clear();
	string valueString = AnyTypeToString(t);
	vector<string> * values = new vector<string>();
	StringSplit(valueString, ".", values);
	for (unsigned short i = 0; i < values->size(); i++)
	{
		long l;
		StringToAnyType(l, values->at(i));
		_decimals.push_back(l);
	}
	delete values;
}

vector<long> DottedDecimal::GetDecimals()
{
	return _decimals;
}

ostream &operator<<(ostream & dataStream, DottedDecimal & dd)
{
	dataStream << dd.GetDottedDecimal();
	return dataStream;
}

bool operator==(DottedDecimal & left, DottedDecimal & right)
{
	// If the value count isn't the same, then false
	if (left.GetDecimals().size() != right.GetDecimals().size())
		return false;

	for (unsigned short i = 0; i < left.GetDecimals().size(); i++)
	{
		// If at any time values don't match, return false
		if (left.GetDecimals().at(i) != right.GetDecimals().at(i))
			return false;
	}

	// If you get here they are the same.
	return true;
}

bool operator!=(DottedDecimal & left, DottedDecimal & right)
{
	// If the value count isn't the same, then true
	if (left.GetDecimals().size() != right.GetDecimals().size())
		return true;

	for (unsigned short i = 0; i < left.GetDecimals().size(); i++)
	{
		// If at any time values don't match, return true
		if (left.GetDecimals().at(i) != right.GetDecimals().at(i))
			return true;
	}

	// If you get here they are the same.
	return false;
}

bool operator>(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has more values than the right side.
	if (left.GetDecimals().size() > right.GetDecimals().size() )
		return true;
	else
		return false;
}

bool operator>=(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is greater, return true;
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has more values than or the same values as the right side.
	return left.GetDecimals().size() >= right.GetDecimals().size();
}

bool operator<(DottedDecimal & left, DottedDecimal & right)
{
// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is less, return true;
		if (left.GetDecimals().at(i) < right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has less values than the right side.
	return left.GetDecimals().size() < right.GetDecimals().size();
}

bool operator<=(DottedDecimal & left, DottedDecimal & right)
{
	// If one has three values and the other has four, only check three
	short count = (left.GetDecimals().size() <= right.GetDecimals().size() ? left.GetDecimals().size() : right.GetDecimals().size());
	for (unsigned short i = 0; i < count; i++)
	{
		// If any compared value is greater, return true;
		if (left.GetDecimals().at(i) > right.GetDecimals().at(i))
			return true;
	}

	// If you get here, then the checked values were the same.
	// Return true if the left side has less values than or the same values as the right side.
	return left.GetDecimals().size() <= right.GetDecimals().size();
}

// Private

template <class T>
string DottedDecimal::AnyTypeToString(const T& t)
{
	std::stringstream ss;
	ss << t;
	return ss.str();
}

template <class T>
void DottedDecimal::StringToAnyType(T& t, std::string inString)
{
	std::stringstream ss(inString);
	ss >> t;
}

void DottedDecimal::StringSplit(string inString, string inDelim, vector<string> * outResults)
{
	int cutAt;
	while( (cutAt = inString.find_first_of(inDelim)) != inString.npos )
	{
		if(cutAt > 0)
		{
			outResults->push_back(inString.substr(0,cutAt));
		}
		inString = inString.substr(cutAt+1);
	}
	if(inString.length() > 0)
	{
		outResults->push_back(inString);
	}
}

Copyright ® Rhyous.com – Linking to this article is allowed without permission and as many as ten lines of this article can be used along with this link. Any other use of this article is allowed only by permission of Rhyous.com.

Leave a Reply