1

I currently have a solution using two HashMaps with matching keys that link the values together (i.e Key: prefix length, Values: Subnet Mask/Number of Addresses available).

Is there a significant design issue here and would it be better practice to merge these HashMaps together using a Tuple value-type, increasing complexity over two simple Maps? - Similar questions give both options but don't seem to give scenarios for when to use one over the other.

Example below for the implementation:

private static HashMap<Integer, Integer> prefixAndNumberOfAddresses;
private static HashMap<Integer, String> prefixAndSubnets;

static {
    prefixAndNumberOfAddresses = new HashMap<Integer, Integer>();
    prefixAndNumberOfAddresses.put(8, 16777214);
    prefixAndNumberOfAddresses.put(9, 8388606);
    prefixAndNumberOfAddresses.put(10, 4194302);
    prefixAndNumberOfAddresses.put(11, 2097150);
    prefixAndNumberOfAddresses.put(12, 1048574);
    prefixAndNumberOfAddresses.put(13, 524286);
    prefixAndNumberOfAddresses.put(14, 262142);
    prefixAndNumberOfAddresses.put(15, 131070);
    prefixAndNumberOfAddresses.put(16, 65534);
    prefixAndNumberOfAddresses.put(17, 32766);
    prefixAndNumberOfAddresses.put(18, 16382);
    prefixAndNumberOfAddresses.put(19, 8190);
    prefixAndNumberOfAddresses.put(20, 4094);
    prefixAndNumberOfAddresses.put(21, 2046);
    prefixAndNumberOfAddresses.put(22, 1022);
    prefixAndNumberOfAddresses.put(23, 510);
    prefixAndNumberOfAddresses.put(24, 254);
    prefixAndNumberOfAddresses.put(25, 126);
    prefixAndNumberOfAddresses.put(26, 62);
    prefixAndNumberOfAddresses.put(27, 30);
    prefixAndNumberOfAddresses.put(28, 14);
    prefixAndNumberOfAddresses.put(29, 6);
    prefixAndNumberOfAddresses.put(30, 2);
}

static {
    prefixAndSubnets = new HashMap<Integer, String>();
    prefixAndSubnets.put(8, "255.0.0.0");
    prefixAndSubnets.put(9, "255.128.0.0");
    prefixAndSubnets.put(10, "255.192.0.0");
    prefixAndSubnets.put(11, "255.224.0.0");
    prefixAndSubnets.put(12, "255.240.0.0");
    prefixAndSubnets.put(13, "255.248.0.0");
    prefixAndSubnets.put(14, "255.252.0.0");
    prefixAndSubnets.put(15, "255.254.0.0");
    prefixAndSubnets.put(16, "255.255.0.0");
    prefixAndSubnets.put(17, "255.255.128.0");
    prefixAndSubnets.put(18, "255.255.192.0");
    prefixAndSubnets.put(19, "255.255.224.0");
    prefixAndSubnets.put(20, "255.255.240.0");
    prefixAndSubnets.put(21, "255.255.248.0");
    prefixAndSubnets.put(22, "255.255.252.0");
    prefixAndSubnets.put(23, "255.255.254.0");
    prefixAndSubnets.put(24, "255.255.255.0");
    prefixAndSubnets.put(25, "255.255.255.128");
    prefixAndSubnets.put(26, "255.255.255.192");
    prefixAndSubnets.put(27, "255.255.255.224");
    prefixAndSubnets.put(28, "255.255.255.240");
    prefixAndSubnets.put(29, "255.255.255.248");
    prefixAndSubnets.put(30, "255.255.255.252");
}
srbrettle
  • 40
  • 1
  • 2
  • 9
  • 3
    It's probably better to write a proper class instead of using a tuple. – Radiodef May 20 '18 at 15:58
  • 2
    You don't even need a hashmap. A proper class could be intelligent enough to compute both available addresses and subnet mask dynamically after you pass the prefix to its constructor. Of course, a hashmap would be a lot faster, but it's a lot more code, as well. – Jan B. May 20 '18 at 16:23

2 Answers2

1

In this case, you'd better use one HashMap with value is a Tuple.

Reason is simple, if you use two HashMap:

  1. When query full data of a key, you must use two lookup agains two HashMap
  2. If you want to print all the subnetmask/number of address, you have to ensure both HashMap have same size
Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
1

Two separate HashMaps are quite cumbersome and error-prone. Merge both into a single HashMap and you save one lookup and some lines of code.

As I stated in the comment, if you need to access that lookup table very frequently (once a second, or 100 times a second), you might be better off with the table lookup. Otherwise, you could go for a programmatic approach. It is a bit slower, for sure, but it's definitely more elegant and more object-oriented.

public class SubnetMask {

    private int prefix;

    public SubnetMask(int prefix) {
        if (prefix < 8 || prefix > 30) {
            throw new IllegalArgumentException("Prefix must be in [8;32]");
        }
        this.prefix = prefix;
    }

    public long getNrOfAvailableAddresses() {
        return (long) Math.pow(2, 32 - this.prefix) - 2;
    }

    // returns something like "255.255.192.0"
    public String getSubnetMaskRepresentation() {
        long bits = 0xffffffff ^ (1 << 32 - this.prefix) - 1;
        return String.format("%d.%d.%d.%d", 
                 (bits & 0x0000000000ff000000L) >> 24, 
                 (bits & 0x0000000000ff0000) >> 16, 
                 (bits & 0x0000000000ff00) >> 8, bits & 0xff);
    }
}

PS.: The translation to the x.x.x.x representation taken from gma's answer in another post.

PPS.: Intellij Idea suggests to simplify the long bits = ... statement. Don't do it, it seems to give a wrong result.

Jan B.
  • 6,030
  • 5
  • 32
  • 53