青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆 - 42  文章 - 3  trackbacks - 0
<2025年9月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

常用鏈接

留言簿(2)

隨筆檔案

文章檔案

網(wǎng)頁收藏

搜索

  •  

最新評(píng)論

閱讀排行榜

評(píng)論排行榜


This note is about book .NET and COM.

Think of XML Web services simply as components or Application Programming Interfaces (APIs) exposed on a Web site rather than a DLL residing on your own computer.

An assembly is a self-describing logical component. Assemblies are units of deployment, units of security, units of versioning, and units of scope for the types contained within. Although an assembly is typically one executable or one DLL, it could be made up of multiple files. 

Any assemblies with type definitions contain corresponding type information describing them. This information is called metadata (data about data). 

Reflection
 is the process of programmatically obtaining type information. Programs can dynamically inspect (“reflect upon”) the metadata for any assemblies, dynamically instantiate objects and invoke members, and even emit metadata dynamically (a technology called Refection Emit). Reflection provides late binding facilities like COM’s IDispatch and IDispatchEx interfaces, type inspection like COM’s ITypeInfo and ITypeInfo2 interfaces, and much more.

How Unmanaged Code Interacts with Managed Code

Three technologies exist that enable the interaction between unmanaged and managed code:

  • Platform Invocation Services (PInvoke)

     1 static class GameSharp
     2 {
     3     /// The native methods in the DLL's unmanaged code.
     4     internal static class UnsafeNativeMethods
     5     {
     6     const string _dllLocation = "CoreDLL.dll";
     7     [DllImport(_dllLocation)]
     8     public static extern void SimulateGameDLL(int a, int b);
     9     }
    10 }

    Choosing a Calling Convention

    The calling convention of an entry point can be specified using another DllImportAttribute named parameter, called CallingConvention. The choices for this are as follows:

    • CallingConvention.Cdecl. The caller is responsible for cleaning the stack. Therefore, this calling convention is appropriate for methods that accept a variable number of parameters (like printf).

    • CallingConvention.FastCall. This is not supported by version 1.0 of the .NET Framework.

    • CallingConvention.StdCall. This is the default convention for PInvoke methods running on Windows. The callee is responsible for cleaning the stack.

    • CallingConvention.ThisCall. This is used for calling unmanaged methods defined on a class. All but the first parameter is pushed on the stack since the first parameter is the this pointer, stored in the ECX register.

    • CallingConvention.Winapi. This isn’t a real calling convention, but rather indicates to use the default calling convention for the current platform. On Windows (but not Windows CE), the default calling convention is StdCall.

    Declare always uses Winapi, and the default for DllImportAttribute is also Winapi. As you might guess, this is the calling convention used by Win32 APIs, so this setting doesn’t need to be used in this chapter’s examples.

     1 using System;
     2 using System.Runtime.InteropServices;
     3 
     4 public class LibWrap
     5 {
     6 // C# doesn't support varargs so all arguments must be explicitly defined. 
     7 // CallingConvention.Cdecl must be used since the stack is  
     8 // cleaned up by the caller. 
     9 
    10 // int printf( const char *format [, argument] )
    11 
    12 [DllImport("msvcrt.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)]
    13 public static extern int printf(String format, int i, double d); 
    14 
    15 [DllImport("msvcrt.dll", CharSet=CharSet.Unicode, CallingConvention=CallingConvention.Cdecl)]
    16 public static extern int printf(String format, int i, String s); 
    17 }
    18 
    19 public class App
    20 {
    21     public static void Main()
    22     {
    23         LibWrap.printf("\nPrint params: %i %f", 99, 99.99);
    24         LibWrap.printf("\nPrint params: %i %s", 99, "abcd");
    25     }
    26 }
  • Mixed-Mode Programming Using Managed Extensions to C++

  • COM Interoperability

         

      Good COM server implementation in C#

      Building COM Objects in C#

     Building COM Servers in .NET








posted @ 2013-06-27 03:32 鷹擊長空 閱讀(344) | 評(píng)論 (0)編輯 收藏
As demand of project, I need to learn this language a little bit more. Although I have written some Python script before, still there is numerous knowledge need to learn.

eg: y = raw_input(‘Enter a number’)
# y is a string

list = [ 'abcd', 786 , 2.23, 'john', 70.2 ] tinylist = [123, 'john']  
print list # Prints complete list
print list[0] # Prints first element of the list
print list[1:3] # Prints elements starting from 2nd till 3rd
print list[2:] # Prints elements starting from 3rd element
print tinylist * 2 # Prints list two times
print list + tinylist # Prints concatenated list

tuple = ( 'abcd', 786 , 2.23, 'john', 70.2 ) tinytuple = (123, 'john')  
print tuple # Prints complete list
print tuple[0] # Prints first element of the list
print tuple[1:3] # Prints elements starting from 2nd till 3rd
print tuple[2:] # Prints elements starting from 3rd element
print tinytuple * 2 # Prints list two times
print tuple + tinytuple # Prints concatenated lists

posted @ 2012-12-20 12:41 鷹擊長空 閱讀(237) | 評(píng)論 (0)編輯 收藏

I didn't use VS2008 for a long time, but today I need to build a project with it. It cost me several hours to solve some small issues. It seems have lots of bug. I will list them as follows:

First of all, I cannot edit the resource file with the default program. Searched with Google, this is a bug of VS. Just replace the slash in absolute including path with double slash;

The second issue is additional lib. In VS2010, multiply lib file names is separate by semicolon, but in VS2009 it is space;
posted @ 2012-10-11 11:08 鷹擊長空 閱讀(279) | 評(píng)論 (0)編輯 收藏
 
在編寫共享庫時(shí),為保證ABI(app binary interface)兼容:
  1 盡量使用C語言 2不要在接口類使用虛函數(shù)和模板; 3 不要改變成員函數(shù)的訪問權(quán)限; 4 不要使用STL 5 不要依賴使用虛擬析構(gòu)函數(shù),最好自己實(shí)現(xiàn),顯式調(diào)用;
6 不要在DLL里面申請內(nèi)存,DLL外釋放,DLL和APP可能不在同一個(gè)內(nèi)存堆;

可重入(reentrant)函數(shù)可以由多于一個(gè)任務(wù)并發(fā)使用,而不必?fù)?dān)心數(shù)據(jù)錯(cuò)誤。相反, 不可重入(non-reentrant)函數(shù)不能由超過一個(gè)任務(wù)所共享,除非能確保函數(shù)的互斥(或者使用信號(hào)量,或者在代碼的關(guān)鍵部分禁用中斷)??芍厝牒瘮?shù)可以在任意時(shí)刻被中斷,稍后再繼續(xù)運(yùn)行,不會(huì)丟失數(shù)據(jù)??芍厝牒瘮?shù)要么使用本地變量,要么在使用全局變量時(shí)保護(hù)自己的數(shù)據(jù)。
Reentrant Function:A function whose effect, when called by two or more threads,is guaranteed to be as if the threads each executed thefunction one after another in an undefined order, even ifthe actual execution is interleaved.
Thread-Safe Function:A function that may be safely invoked concurrently by multiple threads.

函數(shù)可重入的必要條件:
1 不使用任何(局部)靜態(tài)變量或者全局的非常量;
2 不返回任何局部靜態(tài)或者全局非常量指針;
3 僅依賴調(diào)用方的參數(shù);
4 不依賴任何單個(gè)資源的鎖;
5 不調(diào)用任何不可重入的函數(shù);

In classical OS, stack grows downwards. After each push operatation, the value of ebp becomes small, and vice versa.

esp is the top of the stack.

ebp is usually set to esp at the start of the function. Local variables are accessed by subtracting a constant offset from ebp. All x86 calling conventions define ebp as being preserved across function calls. ebp itself actually points to the previous frame's base pointer, which enables stack walking in a debugger and viewing other frames local variables to work.

Most function prologs look something like:
push ebp      ; Preserve current frame pointer
mov ebp, esp  ; Create new frame pointer pointing to current stack top
sub esp, 20   ; allocate 20 bytes worth of locals on stack. 

Then later in the function you may have code like (presuming both local variables are 4 bytes)
mov [ebp-4], eax    ; Store eax in first local
mov ebx, [ebp - 8]  ; Load ebx from second local

objdump is a program for displaying various information about object files. For instance, it can be used as a disassembler to view executable in assembly form. It is part of the GNU Binutils for fine-grained control over executable and other binary data.

For example, to completely disassemble a binary:
objdump -Dslx file


posted @ 2012-07-17 22:20 鷹擊長空 閱讀(331) | 評(píng)論 (0)編輯 收藏

How Cocoa Bindings Work (via KVC and KVO)

Cocoa bindings can be a little confusing, especially to newcomers. Once you have an understanding of the underlying concepts, bindings aren’t too hard. In this article, I’m going to explain the concepts behind bindings from the ground up; first explaining Key-Value Coding (KVC), then Key-Value Observing (KVO), and finally explaining how Cocoa bindings are built on top of KVC and KVO.

 

Key-Value Coding (KVC)

The first concept you need to understand is Key-Value Coding (KVC), as KVO and bindings are built on top of it.

 

Objects have certain "properties". For example, a Person object may have an name property and an address property. In KVC parlance, the Person object has a value for the name key, and for the address key. "Keys" are just strings, and "values" can be any type of object[1]. At it’s most fundamental level, KVC is just two methods: a method to change the value for a given key (mutator), and a method to retrieve the value for a given key (accessor). Here is an example:

 

void ChangeName(Person* p, NSString* newName)

{

    //using the KVC accessor (getter) method

    NSString* originalName = [p valueForKey:@"name"];

 

    //using the KVC mutator (setter) method.

    [p setValue:newName forKey:@"name"];

 

    NSLog(@"Changed %@'s name to: %@", originalName, newName);

}

Now let’s say the Person object has a third key: a spouse key. The value for the spouse key is another Person object. KVC allows you to do things like this:

 

void LogMarriage(Person* p)

{

    //just using the accessor again, same as example above

    NSString* personsName = [p valueForKey:@"name"];

 

    //this line is different, because it is using

    //a "key path" instead of a normal "key"

    NSString* spousesName = [p valueForKeyPath:@"spouse.name"];

 

    NSLog(@"%@ is happily married to %@", personsName, spousesName);

}

Cocoa makes a distinction between "keys" and "key paths". A "key" allows you to get a value on an object. A "key path" allows you to chain multiple keys together, separated by dots. For example, this…

 

[p valueForKeyPath:@"spouse.name"];

is exactly the same as this…

 

[[p valueForKey:@"spouse"] valueForKey:@"name"];

That’s all you need to know about KVC for now.

 

Let’s move on to KVO.

 

Key-Value Observing (KVO)

Key-Value Observing (KVO) is built on top of KVC. It allows you to observe (i.e. watch) a KVC key path on an object to see when the value changes. For example, let’s write some code that watches to see if a person’s address changes. There are three methods of interest in the following code:

 

watchPersonForChangeOfAddress: begins the observing

observeValueForKeyPath:ofObject:change:context: is called every time there is a change in the value of the observed key path

dealloc stops the observing

static NSString* const KVO_CONTEXT_ADDRESS_CHANGED = @"KVO_CONTEXT_ADDRESS_CHANGED"

 

@implementation PersonWatcher

 

-(void) watchPersonForChangeOfAddress:(Person*)p;

{

    //this begins the observing

    [p addObserver:self

        forKeyPath:@"address"

           options:0

           context:KVO_CONTEXT_ADDRESS_CHANGED];

 

    //keep a record of all the people being observed,

    //because we need to stop observing them in dealloc

    [m_observedPeople addObject:p];

}

 

//whenever an observed key path changes, this method will be called

- (void)observeValueForKeyPath:(NSString *)keyPath

                      ofObject:(id)object

                        change:(NSDictionary *)change

                       context:(void *)context;

{

    //use the context to make sure this is a change in the address,

    //because we may also be observing other things

    if(context == KVO_CONTEXT_ADDRESS_CHANGED){

        NSString* name = [object valueForKey:@"name"];

        NSString* address = [object valueForKey:@"address"];

        NSLog(@"%@ has a new address: %@", name, address);

    }       

}

 

-(void) dealloc;

{

    //must stop observing everything before this object is

    //deallocated, otherwise it will cause crashes

    for(Person* p in m_observedPeople){

        [p removeObserver:self forKeyPath:@"address"];

    }

    [m_observedPeople release]; m_observedPeople = nil;

    [super dealloc];

}

 

-(id) init;

{

    if(self = [super init]){

        m_observedPeople = [NSMutableArray new];

    }

    return self;

}

 

@end

This is all that KVO does. It allows you to observe a key path on an object to get notified whenever the value changes.

 

Cocoa Bindings

Now that you understand the concepts behind KVC and KVO, Cocoa bindings won’t be too mysterious.

 

Cocoa bindings allow you to synchronise two key paths[2] so they have the same value. When one key path is updated, so is the other one.

 

For example, let’s say you have a Person object and an NSTextField to edit the person’s address. We know that every Person object has an address key, and thanks to the Cocoa Bindings Reference, we also know that every NSTextField object has a value key that works with bindings. What we want is for those two key paths to be synchronised (i.e. bound). This means that if the user types in the NSTextField, it automatically updates the address on the Person object. Also, if we programmatically change the the address of the Person object, we want it to automatically appear in the NSTextField. This can be achieved like so:

 

void BindTextFieldToPersonsAddress(NSTextField* tf, Person* p)

{

    //This synchronises/binds these two together:

    //The `value` key on the object `tf`

    //The `address` key on the object `p`

    [tf bind:@"value" toObject:p withKeyPath:@"address" options:nil];

}

What happens under the hood is that the NSTextField starts observing the address key on the Person object via KVO. If the address changes on the Person object, the NSTextField gets notified of this change, and it will update itself with the new value. In this situation, the NSTextField does something similar to this:

 

- (void)observeValueForKeyPath:(NSString *)keyPath

                      ofObject:(id)object

                        change:(NSDictionary *)change

                       context:(void *)context;

{

    if(context == KVO_CONTEXT_VALUE_BINDING_CHANGED){

        [self setStringValue:[object valueForKeyPath:keyPath]];

    }       

}

When the user starts typing into the NSTextField, the NSTextField uses KVC to update the Person object. In this situation, the NSTextField does something similar to this:

 

- (void)insertText:(id)aString;

{

    NSString* newValue = [[self stringValue] stringByAppendingString:aString];

    [self setStringValue:newValue];

 

    //if "value" is bound, then propagate the change to the bound object

    if([self infoForBinding:@"value"]){

        id boundObj = ...; //omitted for brevity

        NSString* boundKeyPath = ...; //omitted for brevity

        [boundObj setValue:newValue forKeyPath:boundKeyPath];

    }

}

For a more complete look at how views propagate changes back to the bound object, see my article: Implementing Your Own Cocoa Bindings.

 

Conclusion

That’s that basics of how KVC, KVO and bindings work. The views use KVC to update the model, and they use KVO to watch for changes in the model. I have left out quite a bit of detail in order to keep the article short and simple, but hopefully it has given you a firm grasp of the concepts and principles.

 

Footnotes

[1] KVC values can also be primitives such as BOOL or int, because the KVC accessor and mutator methods will perform auto-boxing. For example, a BOOL value will be auto-boxed into an NSNumber*.

[2] When I say that bindings synchronise two key paths, that’s not technically correct. It actually synchronises a "binding" and a key path. A "binding" is a string just like a key path but it’s not guaranteed to be KVC compatible, although it can be. Notice that the example code uses @"address" as a key path but never uses @"value" as a key path. This is because @"value" is a binding, and it might not be a valid key path.

 

posted @ 2012-07-16 16:27 鷹擊長空 閱讀(311) | 評(píng)論 (0)編輯 收藏
Create a new local repository:
prompt> mkdir /path/to/repo:
prompt> cd /path/to/repo
prompt> git init
Initialized empty Git repository in /path/to/repo/.git/
prompt>
... create file(s) for first commit ...
prompt> git add .
prompt> git commit -m 'initial import'
Created initial commit bdebe5c: initial import.

1 files changed, 1 insertions(+), 0 deletions(-)
Note that the commit action only commits to your local repository.

Change one of my github repo name in two steps:

Firstly, cd to your local git directory, and find out what remote name(s) refer to that URL

$ git remote -v origin  git@github.com:someuser/someproject.git 

Then, set the new URL

$ git remote set-url origin git@github.com:someuser/newprojectname.git 

or in older versions of git, you might need

$ git remote rm origin $ git remote add origin git@github.com:someuser/newprojectname.git 

(origin is the most common remote name, but it might be called something else.)

But if there's lots of people who are working on your project, they will all need to do the above steps, and maybe you don't even know how to contact them all to tell them. That's what #1 is about.

Further reading:

Footnotes:

1 The exact format of your URL depends on which protocol you are using, e.g.

push your local repository into remote repository:
prompt>git push origin master
To amend the last wrong commit:

git commit --amend -m "New commit message"

 

If the commit you want to fix isn’t the most recent one:

  1. git rebase --interactive $parent_of_flawed_commit

    If you want to fix several flawed commits, pass the parent of the oldest one of them.

  2. An editor will come up, with a list of all commits since the one you gave.

    1. Change pick to reword (or on old versions of Git, to edit) in front of any commits you want to fix.
    2. Once you save, git will replay the listed commits. 

  3. Git will drop back you into your editor for every commit you said you want to reword, and into the shell for every commit you wanted to edit. If you’re in the shell:

    1. Change the commit in any way you like.
    2. git commit --amend
    3. git rebase --continue

Most of this sequence will be explained to you by the output of the various commands as you go. It’s very easy, you don’t need to memorise it – just remember that git rebase --interactive lets you correct commits no matter how long ago they were.

Today, when I try to push some code to the remote, it told me the there is a permission issue, I finally fixed it by created a new key, add it to my git account and local account. Here is the process of adding to local


$ git push -u origin master
Permission denied (publickey).
fatal: The remote end hung up unexpectedly

$ ssh -vT git@github.com
OpenSSH_4.6p1, OpenSSL 0.9.8e 23 Feb 2007
debug1: Connecting to github.com [207.97.227.239] port 22.
debug1: Connection established.
debug1: No more authentication methods to try.
Permission denied (publickey).

$  ssh-add -l
Could not open a connection to your authentication agent.

$ eval `ssh-agent`
Agent pid 4968

If you did not have a key, generate one according this 
https://help.github.com/articles/generating-ssh-keys

then add the key
$  ssh-add /c/Users/li/.ssh/key
Identity added: /c/Users/li/.ssh/key

$ ssh -vT git@github.com
OpenSSH_4.6p1, OpenSSL 0.9.8e 23 Feb 2007
debug1: Connecting to github.com [207.97.227.239] port 22.
debug1: Connection established.
debug1: identity file /c/Users/li/.ssh/identity type -1

Hi ***! You've successfully authenticated, but GitHub does not provide shell access.
debug1: channel 0: free: client-session, nchannels 1
debug1: Transferred: stdin 0, stdout 0, stderr 0 bytes in 0.3 seconds
debug1: Bytes per second: stdin 0.0, stdout 0.0, stderr 0.0
debug1: Exit status 1


$ git push -u origin master
Counting objects: 46, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (42/42), done.
Writing objects: 100% (46/46), 21.33 KiB, done.
Total 46 (delta 1), reused 0 (delta 0)

Clone your repository

Create a new repository in a new directory via the following commands.

 

# Switch to home
cd ~
# Make new directory
mkdir repo02

# Switch to new directory
cd ~/repo02
# Clone
git clone ../remote-repository.git . 

 

posted @ 2012-07-09 22:04 鷹擊長空 閱讀(466) | 評(píng)論 (0)編輯 收藏
Chapter 4
Some people find the “90/10” rule helpful: 90 percent of the running time of most programs is spent in only
10 percent of the code (Hennessy and Patterson, 2002)

Use a vector instead of an array whenever possible.
Vectors provide fast (constant time) element insertion and deletion at the end of the vector, but slow
(linear time) insertion and deletion anywhere else. Insertion and deletion are slow because the operation
must move all the elements “down” or “up” by one to make room for the new element or to fill the
space left by the deleted element. Like arrays, vectors provide fast (constant time) access to any of their
elements.
You should use a vector in your programs when you need fast access to the elements, but do not plan to
add or remove elements often. A good rule of thumb is to use a vector whenever you would have used
an array.

The name deque is an abbreviation for a double-ended queue. A deque is partway between a vector and a
list, but closer to a vector. Like a vector, it provides quick (constant time) element access. Like a list, it
provides fast (amortized constant time) insertion and deletion at both ends of the sequence. However,
unlike a list, it provides slow (linear time) insertion and deletion in the middle of the sequence.
You should use a deque instead of a vector when you need to insert or remove elements from either end
of the sequence but still need fast access time to all elements. However, this requirement does not apply
to many programming problems; in most cases a vector or queue should suffice.


A set in STL is a collection of elements. Although the mathematical definition of a set implies an
unordered collection, the STL set stores the elements in an ordered fashion so that it can provide reasonably
fast lookup, insertion, and deletion.
Use a set instead of a vector or list if you want equal performance for insertion, deletion,and lookup.
Note that a set does not allow duplication of elements. That is, each element in the set must be unique. If
you want to store duplicate elements, you must use a multiset.


Chapter8
Initializer lists allow initialization of data members at the time of their creation.
An initializer list allows you to provide initial values for data members as they are created, which is more efficient than assigning values to them later.
However, several data types must be initialized in an initializer list. The following table summarizes them:a、 const data members; b、Reference data members C、Object data members or Superclasses without default constructors
Initializer lists initialize data members in their declared order in the class definition,not their order in the list.

Chapter9
Pass objects by const reference instead of by value.
The default semantics for passing arguments to functions in C++ is pass-by-value. That means that the function or method receives a copy of the variable, not the variable itself. Thus, whenever you pass an object to a function or method the compiler calls the copy constructor of the new object to initialize it. The copy constructor is also called whenever you return an object from a function or method.
posted @ 2012-07-09 19:41 鷹擊長空 閱讀(437) | 評(píng)論 (0)編輯 收藏

print all permutations of a given string. A permutation, also called an “arrangement number” or “order,” is a rearrangement of the elements of an ordered list S into a one-to-one correspondence with S itself. A string of length n has n! permutation.

# include <stdio.h>
  
/* Function to swap values at two pointers */
void swap (char *x, char *y)
{
    char temp;
    temp = *x;
    *x = *y;
    *y = temp;
}
   
/* Function to print permutations of string
   This function takes three parameters:
   1. String
   2. Starting index of the string
   3. Ending index of the string. */
void permute(char *a, int i, int n) 
{
   int j; 
   if (i == n)
     printf("%s\n", a);
   else
   {
        for (j = i; j <= n; j++)
       {
          swap((a+i), (a+j));
          permute(a, i+1, n);
          swap((a+i), (a+j)); //backtrack
       }
   }
  
/* Driver program to test above functions */
int main()
{
   char a[] = "ABC";  
   permute(a, 0, 2);
   getchar();
   return 0;
}

2. find the sum of contiguous subarray within a one-dimensional array of numbers which has the largest sum.
#include<stdio.h>
int maxSubArraySum(int a[], int size)
{
   int max_so_far = 0, max_ending_here = 0;
   int i;
   for(i = 0; i < size; i++)
   {
     max_ending_here = max_ending_here + a[i];
     if(max_ending_here < 0)
        max_ending_here = 0;
     if(max_so_far < max_ending_here)
        max_so_far = max_ending_here;
    }
    return max_so_far;
 
/*Driver program to test maxSubArraySum*/
int main()
{
   int a[] = {-2, -3, 4, -1, -2, 1, 5, -3};
   int max_sum = maxSubArraySum(a, 8);
   printf("Maximum contiguous sum is %d\n", max_sum);
   getchar();
   return 0;
}

posted @ 2012-07-05 17:51 鷹擊長空 閱讀(336) | 評(píng)論 (0)編輯 收藏
From http://www.newsmth.net/nForum/#!article/Apple/136327
窗口
----
  
其實(shí) Mac OS X 的老用戶們都該熟悉了,和 Windows 不一樣,這個(gè)系統(tǒng)里“窗口”并非
最重要的概念,一個(gè)程序的邏輯結(jié)構(gòu)是:  
  
+---------------------------------------------+
| Application                                 |
| +-------------------------+  +-----------+  |
| | Window                  |  | Menu      |  |
| |   +----------------+    |  +-----------+  |
| |   | Control        |    |                 |
| |   | +---------+    |    |                 |
| |   | | Control |    |    |                 |
| |   | +---------+    |    |                 |
| |   +----------------+    |                 |
| +-------------------------+                 |
+---------------------------------------------+
  
也就是說,菜單是獨(dú)立于窗口的存在,有窗口和控件的區(qū)別。這和 Windows 中一切的
本質(zhì)都是窗口有很大的區(qū)別。  
  
雖然 Mac OS X 中區(qū)分 Window, Control 和 Menu 這幾種概念,但并不代表其設(shè)計(jì)上
沒有考慮到它們之間的一致性。在 Carbon 中,這些實(shí)體都是用 FooRef 的形式來表示
的,Ref 就有指針的意思,比如你創(chuàng)建了一個(gè)窗口之后,就會(huì)得到對應(yīng)的  
WindowRef,其實(shí)這就是一個(gè)用來操縱這個(gè)窗口的指針,而你創(chuàng)建控件之后,對應(yīng)的
是 ControlRef,創(chuàng)建菜單對應(yīng)的自然是 MenuRef 了,還是很好理解的吧。  
  
我們這里先只談窗口。很顯然,要?jiǎng)?chuàng)建窗口,還得有些其他的屬性,讓我們看看  
Carbon 的 CreateNewWindow 這個(gè)函數(shù)的原形是怎么要求的:  
  
OSStatus CreateNewWindow (
    WindowClass windowClass,
    WindowAttributes attributes,
    const Rect *contentBounds,
    WindowRef *outWindow
);
  
WindowClass 是一個(gè)常量,我們最常見的一種是 kDocumentWindowClass (也是下面
打算要用的),還有 kDrawerWindowClass,這也很好理解:那種可以伸縮的 Drawer  
嘛,kAlertWindowClass 呢?就是我們常見的提示框了。  
  
WindowAttributes 則是針對具體 WindowClass 再作更仔細(xì)的屬性定制了,這也是一個(gè)  
32 位的無符號(hào)整數(shù),但和 WindowClass 只能 n 選 1 不同,你可以把屬性用位或 (|) 組
合起來使用。反正一時(shí)也記不住那么多,就先設(shè)置為  
kWindowStandardDocumentAttributes | kWindowStandardHandlerAttribute 好了。前
者保證我們的窗口具有其他標(biāo)準(zhǔn)的文檔窗口相同的特性,而后者給窗口加上系統(tǒng)提供的
標(biāo)準(zhǔn) event handler,以自動(dòng)處理一般的 event。下面是用于設(shè)置的代碼:  
  
WindowAttributes windowAttrs;
  
windowAttrs = kWindowStandardDocumentAttributes |
               kWindowStandardHandlerAttribute;
  
直到這里,“event”都還是一個(gè)很模糊的概念,雖然我們前面多次提到了它,但為了避
免過多的講理論,我拖到現(xiàn)在才來介紹它。  
  
Event (事件) 其實(shí)是 Carbon 編程的基礎(chǔ)。鼠標(biāo)點(diǎn)擊、鍵盤輸入、菜單命令都是以  
event 的形式發(fā)出的。窗口需要重繪、移動(dòng)和放縮時(shí),也會(huì)告知你的應(yīng)用程序一個(gè)  
event。當(dāng)你的程序切換到前端或者后端時(shí),你也會(huì)收到 event 告知你這個(gè)信息。
Carbon 程序的工作就是通過回應(yīng) event 來實(shí)現(xiàn)與用戶和系統(tǒng)交互。  
  
Carbon 的 event 處理是基于回調(diào) (callback) 機(jī)制的。你可以定義針對不同 event 類型
的 event handler,然后在 Carbon Event Manager 中注冊 (Install) 之。然后每當(dāng)  
event 發(fā)生時(shí),Carbon Event Manager 就會(huì)調(diào)用你注冊的 handler 函數(shù)。每個(gè) event  
handler 都必須與一個(gè)具體的 event target 對象關(guān)聯(lián)起來,比如 target 是菜單、窗口或
整個(gè)程序。  
  
應(yīng)用程序包含窗口和菜單,窗口包含控件,控件還能進(jìn)一步包含控件。一旦 event 出
現(xiàn),首先得到通知的是最里層的 target,比如點(diǎn)擊 button 的 event 首先發(fā)到 button 控
件上。如果最里面的 target 沒有相關(guān)的 handler,就把 event 傳播到更外層的包含它的  
target 上。Carbon 給窗口和應(yīng)用程序的 event target 提供了標(biāo)準(zhǔn)的 handler。標(biāo)準(zhǔn)  
handler 可以負(fù)責(zé)處理類似窗口針對鼠標(biāo)的操作,比如拖拽,伸縮等等。這樣一來,你
就只需要關(guān)心自己的程序里針對拖拽或伸縮的特殊反映,而不比費(fèi)神于那些所有程序都
通用的部分了。  
  
當(dāng)然,如果你愿意,也可以覆蓋標(biāo)準(zhǔn)的 handler,比如有人可能會(huì)寫個(gè)針對拉伸窗口的  
handler,給窗口的伸縮增加音效。我們這里沒那么復(fù)雜,用標(biāo)準(zhǔn)的就好啦。  
  
第三個(gè)參數(shù)就更好理解了,是一個(gè)指向 Rect 這個(gè)結(jié)構(gòu)體的指針,說明了窗口在屏幕坐
標(biāo)系 [1] 中的位置和大小。這個(gè)東西其實(shí)還是 QuickDraw 中的概念,所以在程序中我
們也調(diào)用 QuickDraw 的 API 來完成設(shè)置:  
  
#define kWindowTop      100
#define kWindowLeft     50
#define kWindowRight    800
#define kWindowBottom   600
  
Rect contentRect;
  
SetRect(&contentRect, kWindowLeft, kWindowTop,
         kWindowRight, kWindowBottom);
  
設(shè)置的正是這個(gè)矩形四個(gè)點(diǎn)的坐標(biāo)。  
  
[1]: 注意屏幕坐標(biāo)系中左上角是 (0, 0)。
  
最后一個(gè)參數(shù)是一個(gè)輸出,也就是我們最終創(chuàng)建出來的那個(gè)新窗口的指針了。所以,我
們一般是這樣創(chuàng)建窗口的:  
  
WindowRef theWindow;
CreateNewWindow(kDocumentWindowClass, windowAttrs,  
                 &contentRect, &theWindow);
  
等等,窗口是創(chuàng)建好了,存在 theWindow 指針里,可窗口的標(biāo)題呢?我們這樣設(shè)置:  
  
SetWindowTitleWithCFString(theWindow, CFSTR("Hello Carbon"));
  
注意這里的 CFSTR 是一個(gè)宏,用于把 C 的 const char * 字符串轉(zhuǎn)換為 Core  
Foundation 定義的 CFStringRef 字符串,對于 CFString 的詳細(xì)介紹可以看 Strings  
Programming Guide for Core Foundation [2],不過其實(shí)現(xiàn)在我們知道它包括的是一個(gè)
數(shù)組和數(shù)組的長度,數(shù)組的元素都是 Unicode 字符 (UniChar),就行了,具體的轉(zhuǎn)換細(xì)
節(jié)暫時(shí)不必考慮。
  
[2]: http://developer.apple.com/documentation/CoreFoundation/Conceptual/
CFStrings/CFStrings.html
  
一切完畢之后,我們就可以顯示這個(gè)窗口了:  
  
ShowWindow(theWindow);
  
下面把完整的代碼列出 (你也可以看附件里面的):  
  
/* hello.c: testing Carbon basics */
  
#include <Carbon/Carbon.h>
  
#define kWindowTop      100
#define kWindowLeft     50
#define kWindowRight    800
#define kWindowBottom   600
  
int main(int argc, char *argv[])
{
     WindowRef         theWindow;
     WindowAttributes  windowAttrs;
     Rect              contentRect;
      
     windowAttrs = kWindowStandardDocumentAttributes |
                   kWindowStandardHandlerAttribute;
  
     SetRect(&contentRect, kWindowLeft,  kWindowTop,
             kWindowRight, kWindowBottom);
  
     CreateNewWindow(kDocumentWindowClass, windowAttrs,
                     &contentRect, &theWindow);
  
     SetWindowTitleWithCFString(theWindow,  
                                CFSTR("Hello Carbon"));
     ShowWindow(theWindow);
     RunApplicationEventLoop();
     return 0;
}
  
這一節(jié)的內(nèi)容,呃,還是超出了我的預(yù)計(jì),你要是有興趣不妨再看看 Carbon Event  
Manager Programming Guide,event 還是一個(gè)比較 tricky 的概念,而我們要到后面
用到的時(shí)候才會(huì)深談。下一節(jié)講菜單的創(chuàng)建。  
posted @ 2012-07-04 10:39 鷹擊長空 閱讀(892) | 評(píng)論 (1)編輯 收藏

The original post is
http://igoro.com/archive/efficient-auto-complete-with-a-ternary-search-tree/

Over the past couple of years, auto-complete has popped up all over the web. Facebook, YouTube, Google, Bing, MSDN, LinkedIn and lots of other websites all try to complete your phrase as soon as you start typing.

Auto-complete definitely makes for a nice user experience, but it can be a challenge to implement efficiently. In many cases, an efficient implementation requires the use of interesting algorithms and data structures. In this blog post, I will describe one simple data structure that can be used to implement auto-complete: a ternary search tree.

Trie: simple but space-inefficient

Before discussing ternary search trees, let’s take a look at a simple data structure that supports a fast auto-complete lookup but needs too much memory: a trie. A trie is a tree-like data structure in which each node contains an array of pointers, one pointer for each character in the alphabet. Starting at the root node, we can trace a word by following pointers corresponding to the letters in the target word.

Each node could be implemented like this in C#:

class TrieNode
{
public const int ALPHABET_SIZE = 26;
public TrieNode[] m_pointers = new TrieNode[ALPHABET_SIZE];
public bool m_endsString = false;
}

Here is a trie that stores words AB, ABBA, ABCD, and BCD. Nodes that terminate words are marked yellow:

 

gif_1

 

Implementing auto complete using a trie is easy. We simply trace pointers to get to a node that represents the string the user entered. By exploring the trie from that node down, we can enumerate all strings that complete user’s input.

But, a trie has a major problem that you can see in the diagram above. The diagram only fits on the page because the trie only supports four letters {A,B,C,D}. If we needed to support all 26 English letters, each node would have to store 26 pointers. And, if we need to support international characters, punctuation, or distinguish between lowercase and uppercase characters, the memory usage grows becomes untenable.

Our problem has to do with the memory taken up by all the null pointers stored in the node arrays. We could consider using a different data structure in each node, such as a hash map. However, managing thousands and thousands of hash maps is generally not a good idea, so let’s take a look at a better solution.

Ternary search tree to the rescue

A ternary tree is a data structure that solves the memory problem of tries in a more clever way. To avoid the memory occupied by unnecessary pointers, each trie node is represented as a tree-within-a-tree rather than as an array. Each non-null pointer in the trie node gets its own node in a ternary search tree.

For example, the trie from the example above would be represented in the following way as a ternary search tree:

image

The ternary search tree contains three types of arrows. First, there are arrows that correspond to arrows in the corresponding trie, shown as dashed down-arrows. Traversing a down-arrow corresponds to “matching” the character from which the arrow starts. The left- and right- arrow are traversed when the current character does not match the desired character at the current position. We take the left-arrow if the character we are looking for is alphabetically before the character in the current node, and the right-arrow in the opposite case.

For example, green arrows show how we’d confirm that the ternary tree contains string ABBA:

 image

And this is how we’d find that the ternary string does not contain string ABD:

image 

Ternary search tree on a server

On the web, a significant chunk of the auto-complete work has to be done by the server. Often, the set of possible completions is large, so it is usually not a good idea to download all of it to the client. Instead, the ternary tree is stored on the server, and the client will send prefix queries to the server.

The client will send a query for words starting with “bin” to the server:

  image

And the server responds with a list of possible words:

image 

Implementation

Here is a simple ternary search tree implementation in C#:

public class TernaryTree
{
private Node m_root = null;
private void Add(string s, int pos, ref Node node)
{
if (node == null) { node = new Node(s[pos], false); }
if (s[pos] < node.m_char) { Add(s, pos, ref node.m_left); }
else if (s[pos] > node.m_char) { Add(s, pos, ref node.m_right); }
else
{
if (pos + 1 == s.Length) { node.m_wordEnd = true; }
else { Add(s, pos + 1, ref node.m_center); }
}
}
public void Add(string s)
{
if (s == null || s == "") throw new ArgumentException();
Add(s, 0, ref m_root);
}
public bool Contains(string s)
{
if (s == null || s == "") throw new ArgumentException();
int pos = 0;
Node node = m_root;
while (node != null)
{
int cmp = s[pos] - node.m_char;
if (s[pos] < node.m_char) { node = node.m_left; }
else if (s[pos] > node.m_char) { node = node.m_right; }
else
{
if (++pos == s.Length) return node.m_wordEnd;
node = node.m_center;
}
}
return false;
}
}

And here is the Node class:

class Node
{
internal char m_char;
internal Node m_left, m_center, m_right;
internal bool m_wordEnd;
public Node(char ch, bool wordEnd)
{
m_char = ch;
m_wordEnd = wordEnd;
}
}

Remarks

For best performance, strings should be inserted into the ternary tree in a random order. In particular, do not insert strings in the alphabetical order. Each mini-tree that corresponds to a single trie node would degenerate into a linked list, significantly increasing the cost of lookups. Of course, more complex self-balancing ternary trees can be implemented as well.

And, don’t use a fancier data structure than you have to. If you only have a relatively small set of candidate words (say on the order of hundreds) a brute-force search should be fast enough.

Further reading

Another article on tries is available on DDJ (careful, their implementation assumes that no word is a prefix of another):

http://www.ddj.com/windows/184410528

If you like this article, also check out these posts on my blog:


posted @ 2012-06-25 23:26 鷹擊長空 閱讀(484) | 評(píng)論 (0)編輯 收藏
僅列出標(biāo)題  下一頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            欧美一区二区三区在线免费观看| 亚洲黄色性网站| 午夜精品在线| 中日韩高清电影网| 99国产精品99久久久久久| 亚洲激情网址| 久久资源在线| 欧美高清不卡| 亚洲破处大片| 亚洲一区二区伦理| 久久狠狠婷婷| 欧美激情中文字幕一区二区| 欧美三级日本三级少妇99| 国产精品九色蝌蚪自拍| 国产视频观看一区| 亚洲欧洲日夜超级视频| 亚洲一区在线直播| 麻豆免费精品视频| 日韩午夜黄色| 久久精品综合一区| 欧美日韩综合在线| 在线成人激情黄色| 亚洲欧美日韩精品久久奇米色影视 | 亚洲乱亚洲高清| 久久综合国产精品台湾中文娱乐网| 久久综合狠狠| 91久久黄色| 亚洲一区区二区| 久久亚洲精品视频| 国产精品毛片va一区二区三区| 狠狠久久亚洲欧美专区| 一区二区三区 在线观看视频| 午夜精品婷婷| 亚洲国产精品第一区二区| 亚洲欧美日韩综合| 欧美日本精品| 黄色一区二区在线| 亚洲免费视频成人| 亚洲第一精品在线| 欧美一区二区视频97| 欧美日韩一级黄| 在线精品国产欧美| 欧美一站二站| 一本一本a久久| 欧美大秀在线观看 | 亚洲日本激情| 亚洲欧美国产另类| 久久精品一区二区| 一级日韩一区在线观看| 女生裸体视频一区二区三区| 国内成人精品一区| 久久九九久久九九| 亚洲一区二区3| 欧美色大人视频| 一本色道久久综合亚洲精品不卡 | 亚洲视频观看| 欧美日韩一级大片网址| 99精品国产在热久久下载| 麻豆精品一区二区av白丝在线| 亚洲欧美国产精品桃花| 国产精品久久久久久久浪潮网站| 宅男噜噜噜66国产日韩在线观看| 欧美激情精品久久久久久久变态| 久久久激情视频| 一区二区三区我不卡| 久久午夜视频| 久久亚洲一区二区| 亚洲激情在线观看视频免费| 欧美好骚综合网| 欧美激情亚洲视频| 亚洲午夜免费视频| 亚洲你懂的在线视频| 国产视频久久网| 理论片一区二区在线| 免费一级欧美片在线观看| 亚洲三级电影在线观看| 亚洲精品在线观看视频| 国产精品va在线播放我和闺蜜| 一区二区三区四区五区精品视频| 另类图片国产| 亚洲国产精品高清久久久| 嫩草影视亚洲| 欧美福利电影网| 亚洲素人在线| 性欧美暴力猛交另类hd| 在线日韩日本国产亚洲| 亚洲国产一区二区在线| 国产精品va| 男女av一区三区二区色多| 欧美精品乱人伦久久久久久| 亚洲一区尤物| 久久精品国产亚洲精品 | 欧美日本在线播放| 欧美亚洲免费电影| 久久一区二区精品| 亚洲视频一区二区| 久久精品国产在热久久| 一区二区三区产品免费精品久久75| 亚洲一区二区3| 亚洲欧洲在线视频| 午夜精品在线视频| 一区二区三区 在线观看视| 欧美一区午夜精品| 一本一本久久a久久精品综合麻豆 一本一本久久a久久精品牛牛影视 | 久久福利资源站| 一区二区三区不卡视频在线观看 | 欧美午夜精品久久久久久人妖| 久久精品亚洲乱码伦伦中文| 欧美成人国产| 久久精精品视频| 欧美日韩免费视频| 欧美va亚洲va香蕉在线| 国产欧美日韩一区二区三区| 亚洲人成网站777色婷婷| 国内揄拍国内精品久久| 一本大道久久a久久综合婷婷| 一区视频在线| 欧美一区二区啪啪| 亚洲欧美日韩一区二区在线| 欧美国产日韩在线观看| 老巨人导航500精品| 国产欧美 在线欧美| 亚洲久久一区| 亚洲精品影院在线观看| 久久久人成影片一区二区三区观看| 午夜精品久久久久久久男人的天堂| 欧美高清视频免费观看| 欧美电影美腿模特1979在线看| 国产美女精品视频免费观看| 99视频有精品| 在线亚洲成人| 欧美日韩一区二区三区在线看| 欧美激情一区二区三区| 亚洲成人在线| 免费成人在线视频网站| 欧美风情在线观看| 午夜久久久久久| 国产精品成人免费| 亚洲欧洲一级| 日韩午夜高潮| 欧美日本一区| 亚洲手机视频| 亚欧成人在线| 国产亚洲欧美另类一区二区三区| 亚洲欧美国内爽妇网| 欧美一区二区免费视频| 国产欧美日韩综合一区在线播放| 亚洲欧美国产va在线影院| 久久成人在线| 一区在线免费观看| 牛夜精品久久久久久久99黑人| 亚洲国产91| 一区二区三区日韩精品视频| 欧美新色视频| 亚洲一区影院| 久久久爽爽爽美女图片| 亚洲电影在线观看| 欧美激情小视频| 99热精品在线观看| 亚洲一二三四久久| 国产欧美日本一区二区三区| 欧美专区日韩视频| 欧美大学生性色视频| 一区二区三区国产精华| 免费一区二区三区| 中日韩美女免费视频网址在线观看 | 中国av一区| 欧美日韩一区二区欧美激情| 亚洲精品中文字幕在线| 亚洲一区二区精品在线| 国产婷婷色一区二区三区在线| 久久久国产精品一区| 亚洲美女性视频| 久久久久久久一区二区三区| 亚洲激情另类| 国产精品亚洲综合| 免费一区二区三区| 午夜精品一区二区三区在线| 老司机免费视频久久| 亚洲免费黄色| 国产综合网站| 久久久久久有精品国产| 亚洲靠逼com| 久久先锋资源| 亚洲影院色无极综合| 亚洲国产精品久久人人爱蜜臀 | 香蕉国产精品偷在线观看不卡| 国产在线乱码一区二区三区| 欧美日韩八区| 久久国产精品久久国产精品| 亚洲乱码国产乱码精品精天堂| 久久疯狂做爰流白浆xx| 亚洲日本va午夜在线影院| 国产精品永久免费| 欧美 日韩 国产 一区| 欧美伊人久久大香线蕉综合69| 欧美成人三级在线| 亚洲免费人成在线视频观看| 久久综合中文字幕| 亚洲素人一区二区|