/// <summary> /// Attempts to find the country code corresponding to /// a given IP address. /// </summary> /// <param name="address">A <see cref="String"/> value /// representing the </param> /// <returns>The two letter country code corresponding to /// the IP address, or <strong>"??"</strong> if it was not /// found.</returns> public String GetCountry(String address) { String [] parts = address.Split('.'); // The first IndexLength bits form the key into the // array of root nodes. Int32 indexBase = ((Int32.Parse(parts[0]) << 8) + Int32.Parse(parts[1])); Int32 index = indexBase >> (_indexOffset - 16); BinaryTrieNode root = base.Roots[index]; // If we don't have a root, we don't have a value. if (null == root) { return(null); } // Calculate the full key... Int32 key = (indexBase << 16) + (Int32.Parse(parts[2]) << 8) + Int32.Parse(parts[3]); // ...and look it up. return((String)root.FindBestMatch(key).UserData); }
protected Object FindBestMatchInternal(Int32 index, Int32 key) { BinaryTrieNode root = _roots[index]; if (null == root) { return(null); } return(root.FindBestMatch(key).UserData); }
/// <summary> /// Adds a key with the given index to the trie. /// </summary> /// <param name="index">The index of the root <see cref="BinaryTrieNode"/> /// for the given key value.</param> /// <param name="key">An <see cref="Int32"/> key value.</param> /// <param name="keyLength">The length in bits of the significant /// portion of the key.</param> /// <returns>The <see cref="BinaryTrieNode"/> that was added to the /// trie.</returns></returns> protected BinaryTrieNode AddInternal(Int32 index, Int32 key, Int32 keyLength) { CountInternal++; BinaryTrieNode root = Roots[index]; if (null == root) { // Create the new root. return(_roots[index] = new BinaryTrieNode(key, keyLength)); } else { // Add the record to the trie. return(root.AddInternal(key, keyLength)); } }
/// <summary> /// Adds a record to the trie using the internal representation /// of an IP address. /// </summary> internal BinaryTrieNode AddInternal(Int32 key, Int32 keyLength) { // Find the common key keyLength Int32 difference = key ^ _key; // We are only interested in matches up to the keyLength... Int32 commonKeyLength = Math.Min(_keyLength, keyLength); // ...so count down from there. while (difference >= _bit[commonKeyLength]) { commonKeyLength--; } // If the new key length is smaller than the common key length, // or equal but smaller than the current key length, // the new key should be the parent of the current node. if ((keyLength < commonKeyLength) || ((keyLength == commonKeyLength) && (keyLength < _keyLength))) { // Make a copy that will be the child node. BinaryTrieNode copy = (BinaryTrieNode)this.MemberwiseClone(); // new BinaryTrieNode(this); // Fill in the child references based on the first // bit after the common key. if ((_key & _bit[keyLength + 1]) != 0) { _zero = null; _one = copy; } else { _zero = copy; _one = null; } _key = key; _keyLength = keyLength; UserData = EmptyData; return(this); } // Do we have a complete match? if (commonKeyLength == _keyLength) { if (keyLength == _keyLength) { return(this); } // Yes. Add the key as a child. if ((key & _bit[_keyLength + 1]) == 0) { // The remainder of the key starts with a zero. // Do we have a child in this position? if (null == _zero) { // No. Create one. return(_zero = new BinaryTrieNode(key, keyLength)); } else { // Yes. Add this key to the child. return(_zero.AddInternal(key, keyLength)); } } else { // The remainder of the key starts with a one. // Do we have a child in this position? if (null == _one) { // No. Create one. return(_one = new BinaryTrieNode(key, keyLength)); } else { // Yes. Add this key to the child. return(_one.AddInternal(key, keyLength)); } } } else { // No. The match is only partial, so split this node. // Make a copy that will be the first child node. BinaryTrieNode copy = (BinaryTrieNode)this.MemberwiseClone(); // new BinaryTrieNode(this); // And create the other child node. BinaryTrieNode newEntry = new BinaryTrieNode(key, keyLength); // Fill in the child references based on the first // bit after the common key. if ((_key & _bit[commonKeyLength + 1]) != 0) { _zero = newEntry; _one = copy; } else { _zero = copy; _one = newEntry; } _keyLength = commonKeyLength; return(newEntry); } }