Untitled

mail@pastecode.io avatar
unknown
c_cpp
a year ago
3.7 kB
3
Indexable
Never
#include <iostream>
#include <string>
#include <set>
#include <vector>
#include <math.h>
using namespace std;

struct Seg {
  long long a, b; // [a, b]
  string t; // tag
  Seg(long long a, long long b, string t) : a(a), b(b), t(t) { } // constructor
  bool operator<(const Seg &that) const { return a < that.a; }
};

std::set<Seg> myset;

// `s` has higher priority before all current segments in `myset`
void insert(Seg s) {
  // myset.lower_bound(x); // 找第一個 >= x的人
  // myset.upper_bound(x); // 找第一個 >  x的人
  // myset.upper_bound(25); // 找到第一個 a > 25 的人
  // prev(myset.upper_bound(25)); // 最後一個 a <= 25 的人
  auto it = myset.upper_bound(s); // 第一個 a > s.a 的人 // BST找東西log(n)
  if (it != myset.begin()) --it; // BST找prev也是worst case log(n), amortize O(1)
  int ctr = 0;
  while (it != myset.end()) { // n log n (執行n次insert,while加起來最多是5n圈)
    Seg cur = *it;
    ++it;
    if (!(s.b < cur.a || cur.b < s.a)) { // 代表有重疊
      myset.erase(cur);
      if (cur.a < s.a) { // 左邊有圖出來
        myset.emplace(cur.a, s.a-1, cur.t);
      }
      if (cur.b > s.b) { // 右邊有圖出來
        myset.emplace(s.b+1, cur.b, cur.t);
      }
    } else {
      if (++ctr == 2) break;
    }
  }
  myset.insert(s); // O(logn)
}


pair<long long, long long> toInt(string ip){
  const char* ip_char = ip.c_str();
  vector<int> v(4, 0);
  int v1, v2, v3, v4, mask;

  bool singleIP = false;
  if (ip.find('/') == string::npos){
    singleIP = true;
  }

  if(singleIP){
    sscanf(ip_char, "%d.%d.%d.%d", &v[0], &v[1], &v[2], &v[3]);

    long long a = 0;
    for(int i = 0; i < v.size(); i++){
      a *= 256;
      a += v[i];
    }
    cout << "insert or search (without mask) a = " << a << endl;

    return make_pair(a, a);
  } 

  sscanf(ip_char, "%d.%d.%d.%d/%d", &v[0], &v[1], &v[2], &v[3], &mask);

  long long a = 0;
  for(int i = 0; i < v.size(); i++){
    a *= 256;
    a += v[i];
  }
  cout << "original a = " << a << endl;

  long long bitMask = 255*256*256*256 + 255*256*256 + 255*256 + 255;
  a = a & (bitMask << (32 - mask));
  cout << "new a = " << a << endl;

  long long b = a + pow(2, 32-mask) - 1; // it is not guaranteed that a is the smallest !!!!!!!??????????

  return make_pair(a, b);
}

void changeFormat(string action, string ip) {
  pair<long long, long long> p = toInt(ip);
  cout << "changeFormat = " << p.first << " " << p.second << " " << action << endl;
  insert(Seg(p.first, p.second, action));
}


string search(string ip){
  pair<long long, long long> p = toInt(ip);
  long long query = p.first;
  Seg s = Seg(query, query, "SEARCH");

  auto it = myset.upper_bound(s); // 第一個 a > s.a 的人 // BST找東西log(n)
  if (it != myset.begin()) --it;

  return it->t;
}


int main() {
  vector<pair<string, string>> v;
  v.push_back(make_pair("ALLOW", "192.168.100.0/24"));
  v.push_back(make_pair("ALLOW", "192.168.0.5/30"));
  v.push_back(make_pair("DENY", "8.8.8.8/0"));
  v.push_back(make_pair("ALLOW", "1.2.3.4"));

  for(int i = v.size()-1; i >= 0; i--){
    changeFormat(v[i].first, v[i].second);
  }

  vector<string> queries;
  queries.push_back("192.168.100.1");
  queries.push_back("8.8.8.8");

  for(int i = 0; i < queries.size(); i++){
    string result = search(queries[i]);
    cout << "result = " << result << endl;
  }


}

/*
Time complexity:
this method -> O(n log n + m log n) = insert + search time

if direct -> O(n * m)

Problem:
the original ip might not be the smallest in the range!!! (Use bitMask to solve it)
What if the changeFormat has different input format??? (a == b when input is not CIDR)

*/