顯示具有 programming 標籤的文章。 顯示所有文章

gravatar

Coding practice of NVDA


My reviewed solution for P*B/SI C*D Engineer writing testing from my colleague and friend. Just for your consideration only, don't copy or publish without any permissions. There is no any warranties to use following in your project and solution.



1a)
class GraphNode {
    std::vector     adj_nodes;
    std::string                 node_name;
public:
    GraphNode(const char* name) : node_name(name) { }
    void                insert(GraphNode* v)    { adj_nodes.push_back(v); }
    
    const std::string&  name() const    { return node_name; }
    int                 size() const    { return adj_nodes.size(); }
    GraphNode*          operator[](int n) const { return adj_nodes[n]; }
    GraphNode*          get(int n) const { return adj_nodes[n]; }
};

1b)
void depthFirstTraversal (const GraphNode *root) {
    std::stack  stack;    
    stack.push(root);    
    while(!stack.empty()) {
        const GraphNode* vertex = stack.top();
        stack.pop();
        std::cout << vertex->name() << std::endl;
        for(int i=0, size=vertex->size(); i < size; ++i )
            stack.push( (*vertex)[i] );
    }
}


1c)
void breadthFirstTraversal (const GraphNode *root) {
    std::queue  queue;    
    queue.push(root);    
    while(!queue.empty()) {
        const GraphNode* vertex = queue.front();
        queue.pop();
        std::cout << vertex->name() << std::endl;
        for(int i=0, size=vertex->size(); i < size; ++i )
            queue.push( (*vertex)[i] );
    }
}


1d)
template struct my_hash {
  size_t operator()(const T* __s) const
  { return (size_t)__s; }
};
typedef __gnu_cxx::hash_map >  visit_hash;
bool hasCycle2 (const GraphNode* vertex, visit_hash& hash) {
    for(int i=0, size=vertex->size(); i < size; ++i ) {
        GraphNode* adj_node = (*vertex)[i];
        if(hash[ adj_node ])
            return true;
        hash[ adj_node ] = true;
        if( hasCycle2( adj_node, hash ) )
            return true;
        hash[ adj_node ] = false;
    }
    return false;
}
bool hasCycle (const GraphNode* root) {
    visit_hash   hash;
    return hasCycle2(root, hash);
}

2)
void showArcPoints(double x, double y, const Arc& arc, int n);
void printArcPoints(const Arc& arc, int n)
{
    const double diameter = arc.radius*2;
    const double cx = 0.5 * (arc.A.x + arc.B.x);
    const double cy = 0.5 * (arc.A.y + arc.B.y);
    const double dx = (arc.B.x - arc.A.x);
    const double dy = (arc.B.y - arc.A.y);
    const double length = sqrt(dx*dx + dy*dy);
    if( length == diameter )
        showArcPoints(cx,cy, arc, n);
    else if(length < diameter ) {
        const double height = sqrt( arc.radius*arc.radius - length*0.5*length*0.5);
        const double tdx = -height*dy/length;
        const double tdy =  height*dx/length;
        showArcPoints(cx+tdx, cx+tdy, arc, n);
        showArcPoints(cx-tdx, cx-tdy, arc, n);
    }
}

void showArcPoints(double x, double y, const Arc& arc, int n)
{
    double radian_A = asin((arc.A.y-y) / arc.radius);
    if(arc.A.x <= x)  radian_A = M_PI - radian_A;
    double radian_B = asin((arc.B.y-y) / arc.radius);
    if(arc.B.x <= x)  radian_B = M_PI - radian_B;
    double radian_diff = radian_A - radian_B;
    if(radian_diff < 0.0)
        radian_diff += M_PI * 2.0;
    radian_diff /= 1.0 * n;
    double radian = radian_A - radian_diff;
    std::cout << setprecision(3);
    std::cout << "(" << arc.A.x << "," << arc.A.y << ") " ;
    for(int i=0; i
        std::cout << "("
                  << arc.radius * cos(radian)
                  << ","
                  << arc.radius * sin(radian)
                  << ") ";
        radian -= radian_diff;
    }
    std::cout << "(" << arc.B.x << "," << arc.B.y << ")";
    std::cout << std::endl;
}

3)
void printDuplicates (const std::vector &items) {
    typedef std::map >   duplicate_hash;
    duplicate_hash   dup_count;  
    for(int i=0, size = items.size(); i < size; ++i )
        dup_count[ items[i] ] ++;
    duplicate_hash::const_iterator dup_iter;
    for(dup_iter = dup_count.begin(); dup_iter != dup_count.end(); ++dup_iter) {
        if(dup_iter->second >= 2)
            std::cout << dup_iter->first << std::endl;
    }
}




gravatar

iPhone SDK Articles

iPhone SDK Articles 有些不錯的簡單 Tutorials。Objective-C 本身語法已經不是重點,重點在於 Interface Builder 的用法,從以前在 Mac OS X 10.4 的 Xcode 用過的建立 attribute、action 到現在的版本都有些不小的差異。在 Table View Tutorial - Part I 還有 screen 動畫可以複習一下新的用法。新的 Interface Builder 視窗真多,已經多到 13" WXGA macbook 螢幕都快容納不下,還好 iPhone 模擬視窗只有那麼一丁點。但是還是外接更大的寬螢幕用起來才是王道。

gravatar

My First iPhone App

This is my first iPhone application written in iPhone OS 2.0 SDK. Unfortunately, it only runs on iPhone simulator not the real iPhone or iPod touch device. Even I use iPhone toolchain from third party to rebuild the source code, some UIKit classes are miss in current iPhone/iPod touch 1.1.4 firmware.
The purpose of this application is to help users to browse the UDN news items and read news page more easily. Rich content web pages with javascript are not user-friendly on mobile device and touch device. However, this might not have chance to run on iPhone platform due to Apple's App Store restrictions and 2.0 firmware.
iPhone SDK provides an integrated environment and simulator to develop applications easily. But under the restriction, the 3rd party iPhone toolchain and jailbreaked environment should be more useful for ordinary developers.

gravatar

Hash Table with Regex

Hash table 是 computer science 常用的一種 data structure。在已知 key 的情況下,可以很快的找到相對應的 value。通常這個 key value 可能是數值,pointer,或是字串;通常字串會經過 hash function 算出一個數字來當作的 key。那如果 key 是 regular expression,當程式在做 lookup 動作時,是拿一串文字去 hash table 找,是否有一個 regular expression 的 key 符合這串文字,並且找出相對應的 value。例如

hash[ "^abc.*$" ] = 1;
print hash[ "abcdef" ]; // output 1
問題可能在於 regular expression 怎麼做 hash function,並且由文字去 lookup 得到相對應的 regular expression 為 key 的 value? 這個問題蠻難的,不過看到的這個應用,倒是並不會完全都是 regex 特殊字元(像是 ^[a-zA-Z]+$)。應用的例子,可能大家都有在用,就是 Firefox add-ons 的 AdBlock Plus。filter 內有上百個廣告 URL 的 patterns(雖然它只提供 wildcard 字元,但是內部是轉成 regex 來 matching),如果使用者 subscribe 多個 filter list,甚至可以多到上千個吧。當 Firefox 瀏覽一個網頁時,少說幾十個網址需要去跟這幾百個 patterns 做比對。當然最簡單的方式就是,每遇到一個網址,就拿去從頭到尾地把 patterns 拿來作 regular expression 的 matching。當然比到了就是可能 white-list or black-list 裡面的一項,看要阻擋還是放行;沒有比到當然就是放行。Regular expression 實際上在比對時,當然所花費的成本比一般 string compare 高很多。 AdBlock Plus 怎麼做呢?其實說穿了就蠻簡單的,事實上它並不是真的完全拿 regular expression 來做出特殊的 hash function。而是用 regular expression 中內含一般文字,像是 "http://ad*.udn.com/*" 這種(會先轉成 /http:\/\/ad.*\.udn\.com\/.*/ 的 regex 格式供 javascript 比對用),裡面穿插了一些普通的字串。而 AdBlock Plus 它會從中去找出這些特徵(它是從 pattern 後半段去找,因為通常大部分 patterns 前面開頭不是 http:// 就是 *.udn.com/* 這種,從頭找對 URL 似乎沒有好處),並且長度是 8 的特徵字串,像是 ".udn.com",並且不包含 regular expression 特殊字元(當然可能找出來不只一種,像是 "udn.com/" 也是 8 個字)。然後就拿這段文字當作 key 去存 hash table。之後瀏覽 udn.com 內容,每次做 URL 比對時候,例如 "http://ad1.udn.com/RealMedia/ads/something.gif",它就從字串的頭開始,取每一段長度 8 的字串出來給 hash table 去找,所以它依序是給 hash table 找了 "http://a", "ttp://ad", "tp://ad1", ... 到了 ".udn.com" 終於在 hash table 中有找到東西,然後當然就把相對應的 regex 拿來比對是不是符合這個 filter pattern。 其實說穿了,前面的問題並沒有解決,如果是這個例子,用上面的做法就非常不適用:
hash[ "[0-9]+" ] = 1;
hash[ "[a-z]+" ] = 2;
hash[ "[A-Z]+" ] = 3;
print hash[ "abc" ];
事實上後面的做法,並不是真的拿 regular expression 去算出 hash 來作 pairing,而只是剛好在 URL filter patterns 上有這種特徵,就是內含部份網址或路徑,也是因為有這些特徵才比較好辨別哪些是正常內容,哪些是廣告才會有的 URL。利用這種特性,剛好去找出裡面的一些 signature 來建立 hash table,用來作為之後比對時加速尋找真正要比對的 patterns,並不是盲目地完全都去一一比較。 Ref 1: Perl Tie::Hash::Regex Match hash keys using Regular Expressions Ref 2: How does Adblock Plus process its filters and which filters are faster?

gravatar

RD = Redo & Debug

聽說 SS 社的 L 大作在 '05 狂 crash,銷售也不佳,後來 training 以及 code review 時機乎最重要的重點就是,注意 pointer。只要遇到 pointer 的情況,有 * or -> 就很容易被 focus。例如 function body 前面加入對 pointer 類型的 parameters 做 check,只要情況不對馬上謝絕掉。或許這招不錯用,至少可以馬上降低 crash 次數,畢竟幾乎所有的 invalid segment access 都可以避掉,立竿見影。至少這樣可以避免得到 crash comment 一枚,因為程式沒到該有的功能所以得到 bug functional。(註:只要列出來 call stack 就是 core dump,所以單純 return 沒做事至少不會出事)。 不過源頭呢?為什麼會有 invalid address 傳進去?當然就是程式有 bug,一定有地方出錯了,所以才讓那個 bug 一直存活下來,然後還傳遞給其他地方使用。現在好了,大家看情況不對,就盡量謝絕掉。那最後一定還是會出錯,只是出錯就會錯在無法避免的地方。可能最終的源頭跟最後出鎚地點相差十萬八千里,但是 AE/QA 就會看 call stack 或執行過哪些 commands 就把 bug submit 給誰。更慘的是,如果是遇到無法 reproduce 的 bugs,更是查不到來源,因為無法再重複一次,但是他就是曾經 core dump 出來給你看。最後只是 RD 猛去 disassemble 那個位址的 assembly code 來看,然後找相對應 source code 那邊是否有 pointer access 沒有保護好或有 bug。 再來是,大家一定遇過 core dump,最常見的就是 windows 的程式執行錯誤。或是 firefox 遇到 crash 也會有。Apple 也有 crash report 功能。裡面有什麼東西,大家一定看過,不外乎就是 call stack、thread list、module list、environment variables、registers、stack dump、memory dump。就連 unix-like 的環境,也可以產生一個 core file。最神奇的是 SS 社,雖然有 segment fault handler,雖然有 coredump file,但是其實裡面是 call stack 而已,連個 registers values、stack dump、memory dump 都沒有。如果是單純的筆誤 bug,很容易看一下相對應的 source code 就查到了。但是大型軟體下,又無法 reproduce,什麼都沒有 dump,只有 call stack function chain,查得到來源才有鬼。