<file_sep>//
//  message_extend.c
//  mycoin
//
//  Created by lx on 14-1-8.
//  Copyright (c) 2014年 lx. All rights reserved.
//
#include "message_extend.h"

extern int read_raw_varint32(unsigned long *tag, void *_buffer, int offset);

enum message_type_t identify_message(void *_buffer, int start_offset){
    unsigned long size;
    
    unsigned long offset = read_raw_varint32(&size, _buffer, start_offset);
    unsigned long tag = 0;
    
    if(offset < size + offset) {
        offset = read_raw_varint32(&tag, _buffer, offset);
        tag = tag>>3;
        if(tag == 1){
            offset = read_raw_varint32(&tag, _buffer, offset);
            return tag;
        }
    }
    return UNKOWN_MESSAGE;
}


enum message_type_t message_convert( char *buf, size_t len, message_t * msg){
    unsigned long Message_get_delimited_size(void *_buffer, int offset);
    /*
     * Tests whether a message can be completely read from the given buffer at
     * the offset. The bytes [offset..offset+length-1] are interpreted.
     *,
     * Returns 1 (true) if buffer[offset..offset+length-1] contains a complete
     * message or 0 (false) otherwise.
     */
    enum message_type_t msg_type = UNKOWN_MESSAGE;
    do{
        msg_type = identify_message(buf,0);
        switch (msg_type) {
            case SECURITY_QUOTE:
                break;
            case WITHDRAW_QUOTE:
                break;
            case CONTRACT_NOTE:
                ContractNote_read_delimited_from(buf, &quote, 0)
                break;
            case ACCOUNT_EXCHANGE_NOTE:
                
                break;
            default:
                break;
        }
    }while (0);
    
    return msg_type;
}<file_sep>//
//  QuoteQueueTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "QuoteQueueTest.h"
#include <typeinfo>

namespace {
   
    TEST(QuoteQueueTest, getQuoteQueue) {
        
        int code = random();
        
        QuoteQueue& quoteQueue = QuoteQueue::getInstance();
        SellQuoteMultiMap * sellQueue = quoteQueue.getSellQuoteQueue(code);
        ASSERT_EQ(typeid(*sellQueue), typeid(SellQuoteMultiMap));
        
        BuyQuoteMultiMap * buyQueue = quoteQueue.getBuyQuoteQueue(code);
        ASSERT_EQ(typeid(*buyQueue), typeid(BuyQuoteMultiMap));
        
        ASSERT_NE(buyQueue, sellQueue);
        
        code = random();
        
        SellQuoteMultiMap * sellQueue2 = quoteQueue.getSellQuoteQueue(code);
        BuyQuoteMultiMap * buyQueue2 = quoteQueue.getBuyQuoteQueue(code);
   
        
        ASSERT_NE(buyQueue2, sellQueue2);
        
        ASSERT_EQ(buyQueue, buyQueue2);
        ASSERT_EQ(sellQueue, sellQueue2);
        

    }
    
}  // namespace<file_sep>//
//  account_exchange.cpp
//  mycoin
//
//  Created by lx on 14-1-9.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#include "account_message.h"

static bool record(session &ses, WithdrawQuote &quote){
    do{
        ses << "insert into exchange_bill(bill_id, bill_type, occur_time, security_code,  quality, client)  values(?, ?, ?, ?, ?, ?)",
        use(quote.billId), use(quote.billType), use(quote.occurTime)
        , use(quote.code), use(quote.quality), use(quote.client);
        
    }while(false);
    
    return true;
    
}

int AccountExchangeProcessor::charge(AccountExchangeNote &note, EventSwitcher& switcher){
    do {        

        
        // 借记depoist资产，贷记资金往来
        if(RedisVoucher::account(note.client, BizAccount::getDeposit(note.code), BizAccount::getExchange(note.code),note.quality)){


    } while (false);
    
    return STATUS_REJECTED;
}

int AccountExchangeProcessor::withdraw(AccountExchangeNote &note, EventSwitcher& switcher){
    do {

        //借记资金往来，贷记deposit
        if(RedisVoucher::account(note.client, BizAccount::getExchange(note.code),BizAccount::getDeposit(note.code), note.quality)){
            tr.commit();
            note.status = STATUS_FINISHED;
        }else{
            tr.rollback();
        }
    } while (false);
    
    return STATUS_REJECTED;
}



<file_sep>//
//  DatabaseAccount.cpp
//  mycoin
//
//  Created by lx on 13-12-15.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "DatabaseAccount.h"

bool DatabaseVoucher::account(time_t occurTime, AccountSuite& suit, const string& debitCode, const string& creditCode,  money_t  money){
    /*
    //debit
    sql << "insert into " <<  detail_table << "(occur_time, debit, credit, owner) values( ?, ?, 0,?)", use(occurTime), use(money), use(owner);
    
    //balance_type 　时间
    sql << "update "  << table << " set occur_time=:occur_time, balance =banalce + " <<money << " where balance_type=" << 0 <<" and owner=:owner ", use(occurTime, "occur_time"),  use(owner, "owner");
    
    //credit
    sql << "insert into " <<  detail_table << "(occur_time, debit, credit, owner) values( ?, 0, ?,?)", use(occurTime),  use(money),use(owner);
    //balance_type 　时间
    sql << "update "  << table << " set occur_time=:occur_time, balance =banalce - " <<money << " where balance_type=" <<0 <<" and owner=:owner ", use(occurTime, "occur_time"),  use(owner, "owner");
     */
    return true;
}


    /*
Account AccountDAOSqlite::get(int id){
    session sql(sqlite3, "mycoin.sqlite");
    int count;
    sql << "select count(*) from invoices", into(count);

    int id = 7;
    sql << "select name from person where id = :id", use(id, "id");

    ofstream file("my_log.txt");
    sql.set_log_stream(&file);


const int BATCH_SIZE = 25;
std::vector<int> ids;
for (int i = 0; i != BATCH_SIZE; ++i)
{
    ids.push_back(i);
}

statement st = (sql.prepare <<
                "insert into numbers(value) values(:val)",
                use(ids));
for (int i = 0; i != 4; ++i)
{
    st.execute(true);
}
}
     */




<file_sep>//
//  test.h
//  mycoin
//
//  Created by lx on 13-12-17.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__test__
#define __mycoin__test__



#endif /* defined(__mycoin__test__) */
<file_sep>//
//  MatchStrategy.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__MatchStrategy__
#define __mycoin__MatchStrategy__
#include "../quote.h"
#include "LevelOfQuoteQueue.h"


/*
 非类型形参
 　　　　2.1 、非类型模板形参：模板的非类型形参也就是内置类型形参，如template<class T, int a> class B{};其中int a就是非类型的模板形参。
 
 　　　　2.2、 非类型形参在模板定义的内部是常量值，也就是说非类型形参在模板的内部是常量。
 
 　　　　2.3、 非类型模板的形参只能是整型，指针和引用，像double，String, String **这样的类型是不允许的。但是double &，double *，对象的引用或指针是正确的。
 
 　　　　2.4、 调用非类型模板形参的实参必须是一个常量表达式，即他必须能在编译时计算出结果。
 
 　　　　2.5 、注意：任何局部对象，局部变量，局部对象的地址，局部变量的地址都不是一个常量表达式，都不能用作非类型模板形参的实参。全局指针类型，全局变量，全局对象也不是一个常量表达式，不能用作非类型模板形参的实参。
 
 　　　　2.6、 全局变量的地址或引用，全局对象的地址或引用const类型变量是常量表达式，可以用作非类型模板形参的实参。
 
 　　　　2.7 、sizeof表达式的结果是一个常量表达式，也能用作非类型模板形参的实参。
 
 　　　　2.8 、当模板的形参是整型时调用该模板时的实参必须是整型的，且在编译期间是常量，比如template <class T, int a> class A{};如果有int b，这时A<int, b> m;将出错，因为b不是常量，如果const int b，这时A<int, b> m;就是正确的，因为这时b是常量。
 
 　　　　2.9 、非类型形参一般不应用于函数模板中，比如有函数模板template<class T, int a> void h(T b){}，若使用h(2)调用会出现无法为非类型形参a推演出参数的错误，对这种模板函数可以用显示模板实参来解决，如用h<int, 3>(2)这样就把非类型形参a设置为整数3。显示模板实参在后面介绍。
 
 　　　　2.10、 非类型模板形参的形参和实参间所允许的转换
 　　　　　　1、允许从数组到指针，从函数到指针的转换。如：template <int *a> class A{}; int b[1]; A<b> m;即数组到指针的转换
 　　　　　　2、const修饰符的转换。如：template<const int *a> class A{}; int b; A<&b> m;   即从int *到const int *的转换。
 　　　　　　3、提升转换。如：template<int a> class A{}; const short b=2; A<b> m; 即从short到int 的提升转换
 　　　　　　4、整值转换。如：template<unsigned int a> class A{};   A<3> m; 即从int 到unsigned int的转换。
 　　　　　　5、常规转换。
 
 1、可以为类模板的类型形参提供默认值，但不能为函数模板的类型形参提供默认值。函数模板和类模板都可以为模板的非类型形参提供默认值。
 
 　　2、类模板的类型形参默认值形式为：template<class T1, class T2=int> class A{};为第二个模板类型形参T2提供int型的默认值。
 
 　　3、类模板类型形参默认值和函数的默认参数一样，如果有多个类型形参则从第一个形参设定了默认值之后的所有模板形参都要设定默认值，比如template<class T1=int, class T2>class A{};就是错误的，因为T1给出了默认值，而T2没有设定。
 
 　　4、在类模板的外部定义类中的成员时template 后的形参表应省略默认的形参类型。比如template<class  T1, class T2=int> class A{public: void h();}; 定义方法为template<class T1,class T2> void A<T1,T2>::h(){}。
 

 */
inline security_quality_t matchTopDown(SecurityQuote &quote, SecurityQuote & peer);
inline security_quality_t matchBottomUp(SecurityQuote &quote, SecurityQuote & peer);

inline security_quality_t marketPriceBuyIn(SecurityQuote &quote, SecurityQuote & peer);
inline security_quality_t marketPriceSellOut(SecurityQuote &quote, SecurityQuote & peer);

#endif /* defined(__mycoin__MatchStrategy__) */
<file_sep>
OBJ=net.o hiredis.o sds.o async.o
TESTS=mycoin-test



# Fallback to gcc when $CC is not in $PATH.
CXX:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
OPTIMIZATION?=-O3
WARNINGS=-Wall -W -Wstrict-prototypes -Wwrite-strings
DEBUG?= -g -ggdb
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
REAL_LDFLAGS=$(LDFLAGS) $(ARCH)


STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
LIB_DIR=/usr/local/lib
INCLUDE_DIR=/usr/local/include

VPATH = match:account

objects = message.o MessageProcessor.o QuoteQueue.o LevelOfQuoteQueue.o  QuoteMatchProcessor.o QuoteWithdrawProcessor.o Account.o DatabaseAccount.o AccountSuiteFactory.o BizAccount.o QuoteAccount.o  ContractNoteProcessor.o AccountExchangeProcessor.o  match.o aroundMatch.o RoutineQuotation.o RedisPublisher.o
all: mycoin test

# Deps (use make dep to generate this)


# Binaries:
message.o: message/message.c message/message.h
MessageProcessor.o: MessageProcessor.cpp MessageProcessor.h message/message.h

QuoteQueue.o: match/QuoteQueue.cpp match/QuoteQueue.h quote.h
LevelOfQuoteQueue.o: match/LevelOfQuoteQueue.cpp  match/LevelOfQuoteQueue.h quote.h
QuoteMatchProcessor.o: match/QuoteMatchProcessor.cpp match/QuoteMatchProcessor.h match/LimitPriceStrategy.h match/MarketPriceStrategy.h match/QuoteProcessor.h match/QuoteProcessorSet.h quote.h Singleton.h
QuoteWithdrawProcessor.o: match/QuoteWithdrawProcessor.cpp match/QuoteWithdrawProcessor.h quote.h Singleton.h



Account.o: account/Account.cpp account/Account.h
DatabaseAccount.o: account/DatabaseAccount.cpp account/DatabaseAccount.h account/Account.h
AccountSuiteFactory.o: account/AccountSuiteFactory.cpp account/AccountSuiteFactory.h account/DatabaseAccount.h account/Account.h
BizAccount.o: account/BizAccount.cpp account/BizAccount.h
QuoteAccount.o: account/QuoteAccount.cpp account/QuoteAccount.h account/MessageProcessor.h quote.h

ContractNoteProcessor.o: account/ContractNoteProcessor.cpp account/ContractNoteProcessor.h account/MessageProcessor.h quote.h
AccountExchangeProcessor.o: account/AccountExchangeProcessor.cpp account/AccountExchangeProcessor.h account/MessageProcessor.h quote.h


match.o: match.cpp match.h
RoutineQuotation.o: RoutineQuotation.cpp RoutineQuotation.h quote.h
RedisPublisher.o: RedisPublisher.cpp RedisPublisher.h quote.h RoutineQuotation.h
aroundMatch.o: aroundMatch.cpp aroundMatch.h RedisPublisher.h

mycoin: MycoinApplication.cpp MycoinApplication.h  $(objects)
	clang++ -v -std=c++11 -stdlib=libc++ -DWORK -o $@ $(REAL_CFLAGS) $(REAL_LDFLAGS) -I. -I$(INCLUDE_DIR) $<  $(objects) $(LIB_DIR)/libuv.dylib /Users/lx/work/soci-3.2.2/build/lib/libsoci_core.dylib /Users/lx/work/soci-3.2.2/build/lib/libsoci_sqlite3.dylib $(LIB_DIR)/libPocoUtil.dylib $(LIB_DIR)/libPocoFoundation.dylib $(LIB_DIR)/libPocoData.dylib  -L$(LIB_DIR) -lpthread -lhiredis

demo: demo.c demo.h quote.h
	$(CC) -o $@ $(REAL_LDFLAGS) $< $(LIB_DIR)/libuv.dylib -lpthread

.cpp.o:
	clang++ -std=c++11 -stdlib=libc++ -DWORK  -c  -I. -I$(INCLUDE_DIR) $<

.c.o:
	$(CC) -std=c99 -pedantic -c $(REAL_CFLAGS) -I. -I$(INCLUDE_DIR) $<

clean:
	-rm -rf $(TESTS) mycoin $(objects) *.gcda *.gcno *.gcov

dep:
	$(CC) -MM *.c


32bit:
	@echo ""
	@echo "WARNING: if this fails under Linux you probably need to install libc6-dev-i386"
	@echo ""
	$(MAKE) CFLAGS="-m32" LDFLAGS="-m32"

gprof:
	$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"

gcov:
	$(MAKE) CFLAGS="-fprofile-arcs -ftest-coverage" LDFLAGS="-fprofile-arcs"

coverage: gcov
	make check
	mkdir -p tmp/lcov
	lcov -d . -c -o tmp/lcov/hiredis.info
	genhtml --legend -o tmp/lcov/report tmp/lcov/hiredis.info

noopt:
	$(MAKE) OPTIMIZATION=""

.PHONY: all test check clean dep install 32bit gprof gcov noopt
<file_sep>//
//  CoinExchangeTestEnvironment.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__CoinExchangeTestEnvironment__
#define __mycoin__CoinExchangeTestEnvironment__

#include <iostream>
//全局事件
class CoinExchangeTestEnvironment : public testing::Environment
{
public:
    /*
     SetUp()方法在所有案例执行前执行
     */
    virtual void SetUp();
    /*
     TearDown()方法在所有案例执行后执行
     */
    virtual void TearDown();
    
};

#endif /* defined(__mycoin__CoinExchangeTestEnvironment__) */
<file_sep>//
//  send_quote.c
//  mycoin
//
//  Created by lx on 14-1-1.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#include <stdio.h>
#include <uv.h>


typedef struct _SecurityQuote{
    security_billId_t billId;
    enum security_bill_t billType;
    time_t occurTime;
    
    security_code_t code;
    security_price_t price;
    security_quality_t quality;
    security_price_t guaranty;
    security_billId_t refBillId;
    bill_status_t status;
    char client[21];
} SecurityQuote;

static uv_shutdown_t shutdown_req;
static uv_write_t write_req;
struct sockaddr_in dest;
static uv_loop_t *loop;

static void write_cb(uv_write_t* req, int status) {
    
    
}

static void close_cb(uv_handle_t* handle) {
    uv_tcp_t socket;
    uv_tcp_init(loop, &socket);
    uv_connect_t connect;
    
    uv_tcp_connect(&connect, &socket, dest, on_connect);
}

static void shutdown_cb(uv_shutdown_t* req, int status) {
    
    uv_close((uv_handle_t*)req->handle, close_cb);
}

void on_connect(uv_connect_t* req, int status){
    
    SecurityQuote* quote = req->data;
    time(&quote.occurTime);

    uv_write(&write_req, req->handle, (char *)&quote, 1, write_cb);
    
    uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
    
}

int send_quote(const char * host, int port, security_code_t code,security_price_t price, security_quality_t quality, security_price_t guaranty, const char *client)
{

    uv_loop_t *loop = uv_default_loop();
    
    quote.code = 1;//2
    quote.billId = (long)random();//hash
    quote.billType =  (security_bill_t)random()%4; // BUY_IN_LIMIT_PRICE, SELL_OUT_LIMIT_PRICE,
    
    quote.quality = random() %10;
    if(quote.billType == BUY_IN_LIMIT_PRICE || quote.billType == SELL_OUT_LIMIT_PRICE ){
        quote.price = 5000 + random()% 2000;
    }else{
        quote.guaranty = quote.quality * 6000; //BUY_IN_MARKET_PRICE,SELL_OUT_MARKET_PRICE,
    }

    
        SecurityQuote quote;
       
        uv_run(loop, UV_RUN_ONCE);
    }
    return 0;
}

int withdraw_quote(const char * host, int port, security_code_t code, security_billId_t refBillId, const char *client)
{
    
    uv_loop_t *loop = uv_default_loop();
    uv_tcp_t socket;
    uv_tcp_init(loop, &socket);
    uv_connect_t connect;
    SecurityQuote quote;
    connect.data = &quote;

    struct sockaddr_in dest = uv_ip4_addr(host, port);
    uv_tcp_connect(&connect, &socket, dest, on_connect);
    
    SecurityQuote quote;
    uv_run(loop, UV_RUN_ONCE);
    
    return 0;
}<file_sep>//
//  Publisher.h
//  mycoin
//
//  Created by lx on 14-1-8.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef __mycoin__Publisher__
#define __mycoin__Publisher__
#include "quote.h"

class Publisher{
public:
    virtual void publish(const security_code_t code, security_price_t price, security_quality_t quality, security_price_t topBuyPrice[], security_quality_t topBuyQty[], int size1, security_price_t topSellPrice[], security_quality_t topSellQty[], int size2 )=0;
    virtual void publish(SecurityQuote &quote)=0;
    void publish(RoutineQuotation &routine){
        routine.publish()
    }
    void publish(message_t* msg){
        if(msg.quote.status != STATUS_FINISHED)
            return;
        switch(msg.quote.msg_type){
            case SecurityQuote:
                Singleton<RoutineQuation>::instance().update(quote);
                Singleton<Publisher>::instance().publish(quote);
            case AccountExchange:
                Singleton<Publisher>::instance().publish(note);
                break;
            case WithdrawQuote:
                Singleton<Publisher>::instance().publish(quote);
                break;
            case  CONTRACT_NOTE:
                Singleton<RoutineQuation>::instance().update(note);
                Singleton<Publisher>::instance().publish(note);
                break;
            default:
                break;
        }
    }
};

#endif /* defined(__mycoin__Publisher__) */
<file_sep>//
//  test.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__test__
#define __mycoin__test__

/*
 宏中的#的功能是将其后面的宏参数进行字符串化操作（Stringizing operator），简单说就是在它引用的宏变量的左右各加上一个双引号。
 #@是加单引号
 ##是拼接符号（Token-pasting operator）。
 例：
 #define paster( n ) token##n
 paster(9)展开后token##n变成token9。
 */

/*
 for (int i = 0; i < x.size(); ++i)
{
    EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i;
}
 */
/*
 布尔值检查
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_TRUE(condition);	EXPECT_TRUE(condition);	condition is true
 ASSERT_FALSE(condition);	EXPECT_FALSE(condition);	condition is false
 
 数值型数据检查
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_EQ(expected, actual);	EXPECT_EQ(expected, actual);	expected == actual
 ASSERT_NE(val1, val2);	EXPECT_NE(val1, val2);	val1 != val2
 ASSERT_LT(val1, val2);	EXPECT_LT(val1, val2);	val1 < val2
 ASSERT_LE(val1, val2);	EXPECT_LE(val1, val2);	val1 <= val2
 ASSERT_GT(val1, val2);	EXPECT_GT(val1, val2);	val1 > val2
 ASSERT_GE(val1, val2);	EXPECT_GE(val1, val2);	val1 >= val2
 
 
 字符串检查
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_STREQ(expected_str, actual_str);	EXPECT_STREQ(expected_str, actual_str);	 the two C strings have the same content
 ASSERT_STRNE(str1, str2);	EXPECT_STRNE(str1, str2);	 the two C strings have different content
 ASSERT_STRCASEEQ(expected_str, actual_str);	EXPECT_STRCASEEQ(expected_str, actual_str);	 the two C strings have the same content, ignoring case
 ASSERT_STRCASENE(str1, str2);	EXPECT_STRCASENE(str1, str2);	 the two C strings have different content, ignoring case
 *STREQ*和*STRNE*同时支持char*和wchar_t*类型的，*STRCASEEQ*和*STRCASENE*却只接收char*
 
 显示返回成功或失败
 直接返回成功：SUCCEED();
 
 返回失败：
 Fatal assertion	Nonfatal assertion
 FAIL();	ADD_FAILURE();
 
 异常检查
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_THROW(statement, exception_type);	EXPECT_THROW(statement, exception_type);	statement throws an exception of the given type
 ASSERT_ANY_THROW(statement);	EXPECT_ANY_THROW(statement);	statement throws an exception of any type
 ASSERT_NO_THROW(statement);	EXPECT_NO_THROW(statement);	statement doesn't throw any exception
 
 Predicate Assertions
 在使用EXPECT_TRUE或ASSERT_TRUE时，有时希望能够输出更加详细的信息，比如检查一个函数的返回值TRUE还是FALSE时，希望能够输出传入的参数是什么，以便失败后好跟踪。因此提供了如下的断言：
 Fatal assertion            Nonfatal assertion          Verifies
 ASSERT_PRED1(pred1, val1);	EXPECT_PRED1(pred1, val1);	pred1(val1) returns true
 ASSERT_PRED2(pred2, val1, val2);	EXPECT_PRED2(pred2, val1, val2);	pred2(val1, val2) returns true
 
 Google人说了，他们只提供<=5个参数的，如果需要测试更多的参数，直接告诉他们。
 bool MutuallyPrime(int m, int n)
 {
 return Foo(m , n) > 1;
 }
 
 TEST(PredicateAssertionTest, Demo)
 {
 int m = 5, n = 6;
 EXPECT_PRED2(MutuallyPrime, m, n);
 }
 当失败时，返回错误信息：
 
 error: MutuallyPrime(m, n) evaluates to false, where
 m evaluates to 5
 n evaluates to 6
 
 如果对这样的输出不满意的话，还可以自定义输出格式，通过如下：
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_PRED_FORMAT1(pred_format1, val1);`	EXPECT_PRED_FORMAT1(pred_format1, val1);	pred_format1(val1) is successful
 ASSERT_PRED_FORMAT2(pred_format2, val1, val2);	EXPECT_PRED_FORMAT2(pred_format2, val1, val2);	pred_format2(val1, val2) is successful
 testing::AssertionResult AssertFoo(const char* m_expr, const char* n_expr, const char* k_expr, int m, int n, int k) {
 if (Foo(m, n) == k)
 return testing::AssertionSuccess();
 testing::Message msg;
 msg << m_expr << " 和 " << n_expr << " 的最大公约数应该是：" << Foo(m, n) << " 而不是：" << k_expr;
 return testing::AssertionFailure(msg);
 }
 
 TEST(AssertFooTest, HandleFail)
 {
 EXPECT_PRED_FORMAT3(AssertFoo, 3, 6, 2);
 }
 
 浮点型检查
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_FLOAT_EQ(expected, actual);	EXPECT_FLOAT_EQ(expected, actual);	 the two float values are almost equal
 ASSERT_DOUBLE_EQ(expected, actual);	EXPECT_DOUBLE_EQ(expected, actual);	 the two double values are almost equal
 
 
 对相近的两个数比较：
 
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_NEAR(val1, val2, abs_error);	EXPECT_NEAR(val1, val2, abs_error);	 the difference between val1 and val2 doesn't exceed the given absolute error
 
 
 同时，还可以使用：
 
 EXPECT_PRED_FORMAT2(testing::FloatLE, val1, val2);
 EXPECT_PRED_FORMAT2(testing::DoubleLE, val1, val2);
 
 类型检查
 类型检查失败时，直接导致代码编不过，难得用处就在这？看下面的例子：
 
 复制代码
 template <typename T> class FooType {
 public:
 void Bar() { testing::StaticAssertTypeEq<int, T>(); }
 };
 
 TEST(TypeAssertionTest, Demo)
 {
 FooType<bool> fooType;
 fooType.Bar();
 }
 
 死亡测试
 Fatal assertion	Nonfatal assertion	Verifies
 ASSERT_DEATH(statement, regex`);	EXPECT_DEATH(statement, regex`);	statement crashes with the given error
 ASSERT_EXIT(statement, predicate, regex`);	EXPECT_EXIT(statement, predicate, regex`);	statement exits with the given error and its exit code matches predicate
 
 
 由于有些异常只在Debug下抛出，因此还提供了*_DEBUG_DEATH，用来处理Debug和Realease下的不同。
 
 正则表达式
 在POSIX系统（Linux, Cygwin, 和 Mac）中，gtest的死亡测试中使用的是POSIX风格的正则表达式
 在Windows系统中，gtest的死亡测试中使用的是gtest自己实现的简单的正则表达式语法。 相比POSIX风格，gtest的简单正则表达式少了很多内容，比如 ("x|y"), ("(xy)"), ("[xy]") 和("x{5,7}")都不支持。
 
 下面是简单正则表达式支持的一些内容：
 matches any literal character c
 \\d	 matches any decimal digit
 \\D	 matches any character that's not a decimal digit
 \\f	 matches \f
 \\n	 matches \n
 \\r	 matches \r
 \\s	 matches any ASCII whitespace, including \n
 \\S	 matches any character that's not a whitespace
 \\t	 matches \t
 \\v	 matches \v
 \\w	 matches any letter, _, or decimal digit
 \\W	 matches any character that \\w doesn't match
 \\c	 matches any literal character c, which must be a punctuation
 .	 matches any single character except \n
 A?	 matches 0 or 1 occurrences of A
 A*	 matches 0 or many occurrences of A
 A+	 matches 1 or many occurrences of A
 ^	 matches the beginning of a string (not that of each line)
 $	 matches the end of a string (not that of each line)
 xy	 matches x followed by y
 
 
 gtest定义两个宏，用来表示当前系统支持哪套正则表达式风格：
 1. POSIX风格：GTEST_USES_POSIX_RE = 1
 2. Simple风格：GTEST_USES_SIMPLE_RE=1
 
 七、死亡测试运行方式
 1. fast方式（默认的方式）
 testing::FLAGS_gtest_death_test_style = "fast";
 2. threadsafe方式
 testing::FLAGS_gtest_death_test_style = "threadsafe";
 
 你可以在 main() 里为所有的死亡测试设置测试形式，也可以为某次测试单独设置。Google Test会在每次测试之前保存这个标记并在测试完成后恢复。如：
 TEST(MyDeathTest, TestOne) {
 testing::FLAGS_gtest_death_test_style = "threadsafe";
 // This test is run in the "threadsafe" style:
 ASSERT_DEATH(ThisShouldDie(), "");
 }
 
 TEST(MyDeathTest, TestTwo) {
 // This test is run in the "fast" style:
 ASSERT_DEATH(ThisShouldDie(), "");
 }
 
 int main(int argc, char** argv) {
 testing::InitGoogleTest(&argc, argv);
 testing::FLAGS_gtest_death_test_style = "fast";
 return RUN_ALL_TESTS();
 }

 注意事项
 1. 不要在死亡测试里释放内存。
 2. 在父进程里再次释放内存。
 3. 不要在程序中使用内存堆检查。
 */

/*
value-parameterized tests　参数化测试数据
 1. 告诉gtest你的参数类型
 添加一个继承自testing::TestWithParam<T>的类，，其中T就是你需要参数化的参数类型，如参数化一个int型的参数
 class IsPrimeParamTest : public::testing::TestWithParam<int>
 {
 
 };
 
 2. 使用宏TEST_P，在TEST_P宏里，用GetParam()获取当前的参数的具体值
 TEST_P(IsPrimeParamTest, HandleTrueReturn)
 {
 int n =  GetParam();
 EXPECT_TRUE(IsPrime(n));
 }
 
 
 3. 使用INSTANTIATE_TEST_CASE_P宏获取要测试的参数范围
 INSTANTIATE_TEST_CASE_P(TrueReturn, IsPrimeParamTest, testing::Values(3, 5, 11, 23, 17));
 
 第一个参数是测试案例的前缀，可以任意取。
 第二个参数是测试案例的名称，需要和之前定义的参数化的类的名称相同，如：IsPrimeParamTest
 第三个参数是可以理解为参数生成器，上面的例子使用test::Values表示使用括号内的参数。Google提供了一系列的参数生成的函数：
 Range(begin, end[, step])	 范围在begin~end之间，步长为step，不包括end
 Values(v1, v2, ..., vN)	 v1,v2到vN的值
 ValuesIn(container) and ValuesIn(begin, end)　从一个C类型的数组或是STL容器，或是迭代器中取值
 Bool()	 取false 和 true 两个值
 Combine(g1, g2, ..., gN)　将g1,g2,...gN进行排列组合，g1,g2,...gN本身是一个参数生成器，每次分别从g1,g2,..gN中各取出一个值，组合成一个元组(Tuple)作为一个参数。
 
 说明：这个功能只在提供了<tr1/tuple>头的系统中有效。gtest会自动去判断是否支持tr/tuple，如果你的系统确实支持，而gtest判断错误的话，你可以重新定义宏GTEST_HAS_TR1_TUPLE=1。
 
 ４参数化后的测试案例名
 命名规则大概为：
 prefix/test_case_name.test.name/index
 
 type-parameterized tests　类型参数化
 gtest提供了应付各种不同类型的数据时的方案，以及参数化类型的方案。
 首先定义一个继承testing::Test的模版类，：
 template <typename T>
 class FooTest : public testing::Test {
 public:
 
 typedef std::list<T> List;
 static T shared_;
 T value_;
 };

 
 接着定义需要测试到的具体数据类型，比如下面定义了需要测试char,int和unsigned int ：
 typedef testing::Types<char, int, unsigned int> MyTypes;
 TYPED_TEST_CASE(FooTest, MyTypes);
 
 使用TYPED_TEST宏写测试案例，在声明模版的数据类型时，使用TypeParam

 TYPED_TEST(FooTest, DoesBlah) {
 // Inside a test, refer to the special name TypeParam to get the type
 // parameter.  Since we are inside a derived class template, C++ requires
 // us to visit the members of FooTest via 'this'.
 TypeParam n = this->value_;
 
 // To visit static members of the fixture, add the 'TestFixture::'
 // prefix.
 n += TestFixture::shared_;
 
 // To refer to typedefs in the fixture, add the 'typename TestFixture::'
 // prefix.  The 'typename' is required to satisfy the compiler.
 typename TestFixture::List values;
 values.push_back(n);
 
 }
 
 上面的例子看上去也像是类型的参数化，但是还不够灵活，因为需要事先知道类型的列表。gtest还提供一种更加灵活的类型参数化的方式，允许你在完成测试的逻辑代码之后再去考虑需要参数化的类型列表，并且还可以重复的使用这个类型列表。例子：

 template <typename T>
 class FooTest : public testing::Test {
 
 };
 
 TYPED_TEST_CASE_P(FooTest);
 
 
使用宏TYPED_TEST_P写测试案例：
 TYPED_TEST_P(FooTest, DoesBlah) {
 // Inside a test, refer to TypeParam to get the type parameter.
 TypeParam n = 0;
 
 }
 
 TYPED_TEST_P(FooTest, HasPropertyA) {  }

 使用REGISTER_TYPED_TEST_CASE_P宏注册，第一个参数是testcase的名称，后面的参数是test的名称
 REGISTER_TYPED_TEST_CASE_P(FooTest, DoesBlah, HasPropertyA);
 
 接着指定需要的类型列表：
 
 typedef testing::Types<char, int, unsigned int> MyTypes;
 INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes);

 */

/*
 gtest提供的运行参数（环境变量、命令行参数或代码里指定）
 三种设置的途径：
 1. 系统环境变量
 2. 命令行参数
 3. 代码中指定FLAG
 三种途径最中后设置的那个会生效。通常情况下，比较理想的优先级为：命令行参数 > 代码中指定FLAG > 系统环境变量
 如果需要在代码中指定FLAG，可以使用testing::GTEST_FLAG这个宏来设置。比如相对于命令行参数--gtest_output，可以使用testing::GTEST_FLAG(output) = "xml:";来设置。注意到了，不需要加--gtest前缀了。同时，推荐将这句放置InitGoogleTest之前，这样就可以使得对于同样的参数，命令行参数优先级高于代码中指定。
 
 如果需要gtest的设置系统环境变量，必须注意的是：
 1. 系统环境变量全大写，比如对于--gtest_output，响应的系统环境变量为：GTEST_OUTPUT
 2. 有一个命令行参数例外，那就是--gtest_list_tests，它是不接受系统环境变量的
 
 参数列表
 了解了上面的内容，我这里就直接将所有命令行参数总结和罗列一下。如果想要获得详细的命令行说明，直接运行你的案例，输入命令行参数：/? 或 --help 或 -help
 
 1. 测试案例集合
 命令行参数	说明
 --gtest_list_tests	使用这个参数时，将不会执行里面的测试案例，而是输出一个案例的列表。
 --gtest_filter
 对执行的测试案例进行过滤，支持通配符
 
 ?    单个字符
 
 *    任意字符
 
 -    排除，如，-a 表示除了a
 :    取或，如，a:b 表示a或b
 比如下面的例子：
 
 ./foo_test 没有指定过滤条件，运行所有案例
 ./foo_test --gtest_filter=* 使用通配符*，表示运行所有案例
 ./foo_test --gtest_filter=FooTest.* 运行所有“测试案例名称(testcase_name)”为FooTest的案例
 ./foo_test --gtest_filter=*Null*:*Constructor* 运行所有“测试案例名称(testcase_name)”或“测试名称(test_name)”包含Null或Constructor的案例。
 ./foo_test --gtest_filter=-*DeathTest.* 运行所有非死亡测试案例。
 ./foo_test --gtest_filter=FooTest.*-FooTest.Bar 运行所有“测试案例名称(testcase_name)”为FooTest的案例，但是除了FooTest.Bar这个案例
 --gtest_also_run_disabled_tests
 执行案例时，同时也执行被置为无效的测试案例。关于设置测试案例无效的方法为：
 
 在测试案例名称或测试名称中添加DISABLED前缀，比如：
 
 复制代码
 // Tests that Foo does Abc.
 TEST(FooTest, DISABLED_DoesAbc) {  }
 
 class DISABLED_BarTest : public testing::Test {  };
 
 // Tests that Bar does Xyz.
 TEST_F(DISABLED_BarTest, DoesXyz) {  }
 复制代码
 --gtest_repeat=[COUNT]
 设置案例重复运行次数，非常棒的功能！比如：
 
 --gtest_repeat=1000      重复执行1000次，即使中途出现错误。
 --gtest_repeat=-1          无限次数执行。。。。
 --gtest_repeat=1000 --gtest_break_on_failure     重复执行1000次，并且在第一个错误发生时立即停止。这个功能对调试非常有用。
 --gtest_repeat=1000 --gtest_filter=FooBar     重复执行1000次测试案例名称为FooBar的案例。
 
 
 2. 测试案例输出
 
 命令行参数	说明
 --gtest_color=(yes|no|auto)	输出命令行时是否使用一些五颜六色的颜色。默认是auto。
 --gtest_print_time	输出命令行时是否打印每个测试案例的执行时间。默认是不打印的。
 --gtest_output=xml[:DIRECTORY_PATH\|:FILE_PATH]
 将测试结果输出到一个xml中。
 
 1.--gtest_output=xml:    不指定输出路径时，默认为案例当前路径。
 2.--gtest_output=xml:d:\ 指定输出到某个目录
 3.--gtest_output=xml:d:\foo.xml 指定输出到d:\foo.xml
 如果不是指定了特定的文件路径，gtest每次输出的报告不会覆盖，而会以数字后缀的方式创建。xml的输出内容后面介绍吧。
 
 
 3. 对案例的异常处理
 
 命令行参数	说明
 --gtest_break_on_failure	调试模式下，当案例失败时停止，方便调试
 --gtest_throw_on_failure	当案例失败时以C++异常的方式抛出
 --gtest_catch_exceptions
 是否捕捉异常。gtest默认是不捕捉异常的，因此假如你的测试案例抛了一个异常，很可能会弹出一个对话框，这非常的不友好，同时也阻碍了测试案例的运行。如果想不弹这个框，可以通过设置这个参数来实现。如将--gtest_catch_exceptions设置为一个非零的数。
 
 注意：这个参数只在Windows下有效。
 
 
 四、XML报告输出格式
 复制代码
 <?xml version="1.0" encoding="UTF-8"?>
 <testsuites tests="3" failures="1" errors="0" time="35" name="AllTests">
 <testsuite name="MathTest" tests="2" failures="1"* errors="0" time="15">
 <testcase name="Addition" status="run" time="7" classname="">
 <failure message="Value of: add(1, 1)  Actual: 3 Expected: 2" type=""/>
 <failure message="Value of: add(1, -1)  Actual: 1 Expected: 0" type=""/>
 </testcase>
 <testcase name="Subtraction" status="run" time="5" classname="">
 </testcase>
 </testsuite>
 <testsuite name="LogicTest" tests="1" failures="0" errors="0" time="5">
 <testcase name="NonContradiction" status="run" time="5" classname="">
 </testcase>
 </testsuite>
 </testsuites>
 */
/*
 在C++中，为了支持RTTI提供了两个操作符：dynamic_cast和typeid。
 dynamic_cast允许运行时刻进行类型转换，从而使程序能够在一个类层次结构中安全地转化类型，与之相对应的还有一个非安全的转换操作符static_cast，
 
 typeid是C++的关键字之一，等同于sizeof这类的操作符。typeid操作符的返回结果是名为type_info的标准库类型的对象的引用（在头文件typeinfo中定义），它的表达式有两种形式。
 typeid(type) 类型ID
 typeid(expr)　运行时刻类型ID
 如果表达式的类型是类类型且至少包含有一个虚函数，则typeid操作符返回表达式的动态类型，需要在运行时计算；否则，typeid操作符返回表达式的静态类型，在编译时就可以计算。
 ISO C++标准并没有确切定义type_info，确切定义与编译器的实现相关，标准规定必需提供如下四种操作：
 t1 == t2	 如果两个对象t1和t2类型相同，则返回true；否则返回false
 t1 != t2	 如果两个对象t1和t2类型不同，则返回true；否则返回false
 t.name()	 返回类型的C-style字符串，类型名字用系统相关的方法产生
 t1.before(t2)	 返回指出t1是否出现在t2之前的bool值
 
ASSERT_EQ(typeid(*sellQueue), typeid(SellQuoteMultiMap));
 
 type_info类提供了public虚 析构函数，以使用户能够用其作为基类。它的默认构造函数和拷贝构造函数及赋值操作符都定义为private，不能定义或复制type_info类型的对象。程序中创建type_info对象的唯一方法是使用typeid操作符。type_info的name成员函数返回C-style的字符串，表示相应的类型名，这个返回的类型名与程序中使用的相应类型名并不一定一致，这具体由编译器的实现所决定的，标准只要求实现为每个类型返回唯一的字符串。
 
 当typeid操作符的操作数是不带有虚函数的类类型时，typeid操作符会指出操作数的类型，而不是底层对象的类型。
 如果typeid操作符的操作数是至少包含一个虚拟函数的类类型时，并且该表达式是一个基类的引用，则typeid操作符指出底层对象的派生类类型。而指向基类的指针不是类类型，返回基类的类型。
 
 对于多态类实例，想得到实际的类名称，需要使用到RTTI，这需要在编译的时候加上参数"/GR"
 */


#include <iostream>

#endif /* defined(__mycoin__test__) */
<file_sep>//
//  MarketPriceStrategyTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "MarketPriceStrategyTest.h"
#include <typeinfo>

namespace {

    TEST(BuyInMarketPriceStrategy, match) {
        BuyInMarketPriceStrategy<5> strategy;
        //测５档以上
        SecurityQuote quote,cpmQuote;
        SecurityQuote peer,cpmPeer;
        security_quality_t qty;
        
        security_code_t code = random();
        quote.code = code;
        peer.code = code;
        
        quote.quality = random();
        peer.quality = random();
        
        quote.guaranty = random();
        peer.price = random();
        memcpy(&cpmQuote, &quote);
        memcpy(&cpmpeer, &peer);
        
        qty = strategy.match(quote, peer);
        ASSERT_GE(quote.guaranty,0);
        ASSERT_EQ(qty, cmpQuote.quality - quote.quality);
        ASSERT_EQ(qty, peer.quality - cmpPeer.quality);
        ASSSERT_GE(cmpQuote.quality, qty * peer.price);
        
        quote.guaranty = cmpQuote.guaranty;
        quote.quality -= qty;
        ASSERT_EQ(0, memcpm(&cmpQuote,&quote));
        peer.quality += qty;
        ASSERT_EQ(0, memcpm(&cmpPeer,&peer));
        
        if(cmpQuote.guaranty >= peer.price ){
            ASSERT_GT(qty,0);
            quote.guaranty = peer.price  -1;
            ASSERT_EQ(strategy.match(quote, peer),0);
        }else{
            ASSERT_EQ(qty,0);
            quote.quality = peer.price +1;
            ASSERT_GT(strategy.match(quote, peer),0);
        }
        
        quote.quality = - random();
        qty = strategy.match(quote, peer);
        ASSERT_EQ(0, qty);
    }
    
    TEST(SellOutMarketPriceStrategy, match) {
        SellOutMarketPriceStrategy<5> strategy;
        SecurityQuote quote,cpmQuote;
        SecurityQuote peer,cpmPeer;
        security_quality_t qty;
        
        security_code_t code = random();
        quote.code = code;
        peer.code = code;
        
        quote.quality = random();
        peer.quality = random();
        
        quote.guaranty = random();
        peer.price = random();
        memcpy(&cpmQuote, &quote);
        memcpy(&cpmpeer, &peer);
        
        qty = strategy.match(quote, peer);
        
        ASSERT_GE(quote.guaranty,0);
        ASSERT_EQ(qty, cmpQuote.quality - quote.quality);
        ASSERT_EQ(qty, peer.quality - cmpPeer.quality);
        
        quote.guaranty = cmpQuote.guaranty;
        quote.quality -= qty;
        ASSERT_EQ(0, memcpm(&cmpQuote,&quote));
        peer.quality += qty;
        ASSERT_EQ(0, memcpm(&cmpPeer,&peer));
        
        if(cmpQuote.guaranty >= peer.price ){
            ASSERT_GT(qty,0);
            quote.guaranty = peer.price  -1;
            ASSERT_EQ(strategy.match(quote, peer),0);
        }else{
            ASSERT_EQ(qty,0);
            quote.quality = peer.price +1;
            ASSERT_GT(strategy.match(quote, peer),0);
        }
        
        quote.quality = - random();
        qty = strategy.match(quote, peer);
        ASSERT_EQ(0, qty);


    }
    
}  // namespace<file_sep>//
//  message_extend.h
//  mycoin
//
//  Created by lx on 14-1-8.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef mycoin_message_extend_h
#define mycoin_message_extend_h
#include "message.h"

#ifdef __cplusplus
extern "C" {
#endif
    enum message_type_t identify_message(void *_buffer, int start_offset);
    
    typedef union message_u{
        SecurityQuote quote;
        WithdrawQuote withdraw;
        ContractNote note;
        AccountExchangeNote note;
    }message_t;
    // 宏要能把 类型 置换掉 #define message.msg_type message.quote.msg_type
    enum message_type_t message_convert( char *buf, size_t len, message_t * msg);
#ifdef __cplusplus
}
#endif
#endif
<file_sep>//
//  matchTest.cpp
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "matchTest.h"
#include "../quote.h"
#include "readerwriterqueue.h"

extern int matchQuote(SecurityQuote * quote, ReaderWriterQueue<ContractNote > *notes);
template<typename QuoteMultiMap1, typename QuoteMultiMap2>
security_price_t matchQueue(SecurityQuote *quote, QuoteMultiMap1* selfQueue, QuoteMultiMap2 *peerQueue,ReaderWriterQueue<ContractNote > *notes, MatchStrategy &strategy, BalanceStrategy<QuoteMultiMap1, QuoteMultiMap2> &balance);
template<typename QuoteMultiMap>
void withdrawQuote(SecurityQuote *quote, QuoteMultiMap *queue,ReaderWriterQueue<ContractNote > *notes);
QuoteProcessor & getQuoteProcessor(SecurityQuote *quote);

void matchQuote(SecurityQuote * quote, ReaderWriterQueue<ContractNote > *notes);
namespace {
    
    // The fixture for testing class .
    //class MatchTest :public ::testing::TestWithParam<int>
    //测试内容，股价优先，时间优先，不同类型的quote，撤销单，市价，限价
    

    class MatchTest : public ::testing::Test {
       
    protected:
        // You can remove any or all of the following functions if its body
        // is empty.
        
        MatchTest() {
            // You can do set-up work for each test here.
        }
        
        virtual ~MatchTest() {
            // You can do clean-up work that doesn't throw exceptions here.
        }
        
        /*
         SetUpTestCase() 方法在第一个TestCase之前执行
         */
        static void SetUpTestCase() {
            shared_resource_ = new ;
        }
        /*
         TearDownTestCase() 方法在最后一个TestCase之后执行
         */
        static void TearDownTestCase() {
            delete shared_resource_;
            shared_resource_ = NULL;
        }
        // Some expensive resource shared by all tests.
        static T* shared_resource_;
        
        
        // If the constructor and destructor are not enough for setting up
        // and cleaning up each test, you can define the following methods:
        //SetUp()方法在每个TestCase之前执行
        virtual void SetUp() {
            // Code here will be called immediately after the constructor (right
            // before each test).

            time(&quote.occurTime);
            quote.code = 1;//2
            quote.billId = (long)random();//hash
            quote.billType =  (security_bill_t)random()%4; // BUY_IN_LIMIT_PRICE, SELL_OUT_LIMIT_PRICE,
            
            quote.quality = random() %10;
            if(quote.billType == BUY_IN_LIMIT_PRICE || quote.billType == SELL_OUT_LIMIT_PRICE ){
                quote.price = 5000 + random()% 2000;
            }else{
                quote.guaranty = quote.quality * 6000; //BUY_IN_MARKET_PRICE,SELL_OUT_MARKET_PRICE,
            }
            

        }
        
        //TearDown()方法在每个TestCase之后执行
        virtual void TearDown() {
            // Code here will be called immediately after each test (right
            // before the destructor).
            
        }
        
        // Objects declared here can be used by all tests in the test case.
        ReaderWriterQueue<ContractNote > notes(1024);
        SecurityQuote quote;
    };

    TEST_F(MatchTest, withdrawQuote) {
        //撤销单
        //撤销买单，撤销卖单-简单，空单时
        //　有单时
        //　单已全部成交
        //　单成交部分
        //　单完全没成交
        //限价单
        //市价单
    }
}  // namespace
<file_sep>//
//  ContractNoteProcessor.h
//  mycoin-account
//
//  Created by lx on 13-12-25.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin_account__ContractNoteProcessor__
#define __mycoin_account__ContractNoteProcessor__

#include "MessageProcessor.h"

class ContractNoteProcessor:public EventProcessor{
protected:

public:
    ContractNoteProcessor(message_type msg_type, EventSwitcher* processorMap)
    :MessageProcessor(msg_type,processorMap){
        
    }
    
    virtual int execute(message_t *msg, EventSwitcher &switcher){
        return execute(*((ContractNote*)&msg), switcher);
    }

    int execute(ContractNote &note,EventSwitcher &switcher){
        switch (note.status) {
            case STATUS_NEW:
                account(note, switcher);
                return EVS_ACCEPTED;
            case STATUS_ACCOUNTED:
                notify
            default:
                return EVS_REJECTED;
        }
    }
                
    void account(ContractNote &note,EventSwitcher &switcher);
    void notify(ContractNote &note){
        event ;
        event.data = note;
        switcher.push(event);
    }
                
};

#endif /* defined(__mycoin_account__ContractNoteProcessor__) */
<file_sep>//
//  LevelOfQuoteTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__LevelOfQuoteTest__
#define __mycoin__LevelOfQuoteTest__

#include "gtest/gtest.h"
#include "../LevelOfQuoteQueue.h"

#endif /* defined(__mycoin__LevelOfQuoteTest__) */
<file_sep>//
//  account_quote.cpp
//  mycoin
//
//  Created by lx on 14-1-9.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#include "account_message.h"

static bool record(session &ses, SecurityQuote &quote){
    do{
        ses << "insert into quote_bill(bill_id, bill_type, occur_time, status, security_code, price, quality, guaranty,client)  values(?, ?, ?, ?, ?, ?, ?, ?,?)",
        use(quote.billId), use(quote.billType) , use(quote.occurTime), use(quote.status)
            ,use(quote.code), use(quote.price), use(quote.quality), use(quote.guaranty)
            , use(( char*)quote->client);

        
    }while(false);
    
    return true;
    
}

int QuoteProcessor::match(SecurityQuote &quote,EventSwitcher &switcher){
    Singleton<Match>::instance().push(quote); //跨线程要明显的表示出来，不好用now
}

int QuoteProcessor::buyInPrepare(session &ses, SecurityQuote &quote){
    do {
        transaction tr(ses);
        if(!record(ses, quote))
            break;
        AccountSuite* suite = AccountSuiteFactory::instance(ses).getSuite(quote.client);
        
        //买方 借记订金，贷记现金
        if(AccountingVoucher::account(*suite, ACCOUNT_DEPOSIT, ACCOUNT_SUBSCRIPTION,quote.guaranty))
            break;
        
        tr.commit();
        quote.status = STATUS_ACCEPTED;
        return quote.status;
    } while (false);
    
    
    return STATUS_REJECTED;
}

static int sellOutPrepare(session &ses, SecurityQuote &quote){
    do{
        transaction tr(ses);
        if(!record(ses, quote))
            break;
        
        //取消 借记deposit，贷记订金subscription
        
        AccountSuite& suite = *AccountSuiteFactory::instance(ses).getSuite(quote.client);
        if(AccountingVoucher::account(suite, ACCOUNT_DEPOSIT, ACCOUNT_SUBSCRIPTION, quote.guaranty))
            break;
        tr.commit();
        quote.status = STATUS_FINISHED;
        
        return quote.status;
    }while(false);
    
    return STATUS_REJECTED;
}

int prepareQuote(SecurityQuote &quote){
    switch(quote.billType){
        case BUY_IN_LIMIT_PRICE:
        case BUY_IN_MARKET_PRICE:
            return buyInPrepare(ses, &quote);
        case SELL_OUT_LIMIT_PRICE:
        case SELL_OUT_MARKET_PRICE:
            return sellOutPrepare(ses, &quote);
        default:
            return STATUS_REJECTED;
    }
}

static int buyInAccount(session &ses, SecurityQuote &quote){
    
    do{
        transaction tr(ses);
        ses << "update quote_bill set status = " << STATUS_FINISHED<<" where id = ?" , use(quote.billId);
        
        AccountSuite& suite = *AccountSuiteFactory::instance(ses).getSuite(quote.client);
        //取消 借记金融资产，贷记可供出售金融资产
        if(AccountingVoucher::account(suite, BizAccount::getDeposit(quote.code), BizAccount::getForsale(quote.code), quote.quality))
            break;
        tr.commit();
        quote.status = STATUS_FINISHED;
        
        return quote.status;
    }while(false);
    
    return STATUS_REJECTED;
}


static int sellOutAccount(session &ses, SecurityQuote &quote){
    
    do{
        transaction tr(ses);
        
        ses << "update quote_bill set status = ? where id = ?",use((int)STATUS_FINISHED), use(quote.billId);
        
        //取消 借记deposit，贷记订金subscription
        
        AccountSuite& suite = *AccountSuiteFactory::instance(ses).getSuite(quote.client);
        if(AccountingVoucher::account(suite, ACCOUNT_DEPOSIT, ACCOUNT_SUBSCRIPTION, quote.guaranty))
            break;
        tr.commit();
        quote.status = STATUS_FINISHED;
        
        return quote.status;
    }while(false);
    
    return STATUS_REJECTED;
    
}

int accountQuote(SecurityQuote &quote){
    switch(quote.billType){
        case BUY_IN_LIMIT_PRICE:
        case BUY_IN_MARKET_PRICE:
            return buyInAccount(ses, quote);
        case SELL_OUT_LIMIT_PRICE:
        case SELL_OUT_MARKET_PRICE:
            return sellOutAccount(ses, quote);
        default:
            return STATUS_REJECTED;
    }
}<file_sep>//
//  RoutineQuotation.h
//  mycoin
//
//  Created by lx on 13-12-24.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__RoutineQuotation__
#define __mycoin__RoutineQuotation__
/*
routine quotation 日常行情
成交价　时间间隔内的平均价格
成交量　时间间隔内的合计
top行情　实时，因为未成交的top报价也会包含在内，所以包含了历史情况
*/
#include <time.h>
#include "quote.h"
#include <map>
#include "Publisher.h"

using namespace std;

#define MAX_ROUTINE_LEVEL 10

class RoutineQuotation{

private:
    typedef map<security_price_t, security_quality_t> SellQuoteRoutine;
    typedef map<security_price_t, security_quality_t,  greater<int>> BuyQuoteRoutine;

    struct InnerRoutine{
        security_price_t sum=0;
        security_quality_t  qty=0;
        SellQuoteRoutine topSells;
        BuyQuoteRoutine topBuys;
    };
    typedef map<security_code_t,struct InnerRoutine> InnerRoutineMap;

    InnerRoutineMap innerMap;
    
    static inline void fill_zero(InnerRoutine & data){
        data.sum = data.qty = 0;
    }
private:
    template<typename TopQuotes>
    inline void updateTopQuote(TopQuotes& tops, security_price_t price, security_quality_t qty ){
        typename TopQuotes::iterator iter = tops.find(price);
        if(iter != tops.end()){
            iter->second += qty;
        }else{
            tops[price] = qty;
        }
    }
    
public:
    inline void reset()  {
        for (InnerRoutineMap::iterator iter=innerMap.begin(); iter!= innerMap.end(); iter++) {
            
            iter->second.sum = iter->second.qty = 0;
        }
        //for_each(innerMap.begin(), innerMap.end(), fill_zero);
    }
    
    void publish(Publisher &publisher);
    int update(message_t *msg);
    int update(SecurityQuote &quote);
    int update(ContractNote &note);
};

#endif /* defined(__mycoin__RoutineQuotation__) */
<file_sep>//
//  aroundMatch.cpp
//  mycoin-account
//
//  Created by lx on 13-12-25.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include <stdio.h>
#include <unistd.h>
#include <uv.h>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>

#include "quote.h"
#include "aroundMatch.h"
#include "readerwriterqueue.h"
#include "account/Account.h"
#include "RoutineQuotation.h"

#include <hiredis/hiredis.h>
#include <hiredis/async.h>
#include <hiredis/adapters/libuv.h>
#include "Singleton.h"
#include "RedisPublisher.h"
#include "message/message_extend.h"

#include "WithdrawProcessor.h"
#include "QuoteProcessor.h"
#include "MessageProcessor.h"
#include "AccountExchangeProcessor.h"
#include "ContractNoteProcessor.h"

#include "queue/queue_quote.h"
#include "account/account_message.h"
#include "notify/notify.h"

using namespace std;
using namespace moodycamel;
static uv_loop_t *loop;

uv_buf_t alloc_message_buffer(uv_handle_t* handle, size_t suggested_size) {
    size_t len = suggested_size > 0 ? suggested_size : sizeof(message_t);
    char* base = (char *)malloc(len);
    return uv_buf_init(base, len);
}


void on_client_close(uv_handle_t* handle){
    free(handle);
}

void on_message_received(uv_stream_t* stream,ssize_t nread, uv_buf_t buf){
    do{
        if(nread < 0)
            break;
        assert(nread == buf.len);
        
        message_t msg;
        if(UNKOWN_MESSAGE == message_convert(buf.base, buf.len, &msg){
            break;
        }
        //消息分类， quote类 withdraw，quote，不同用户并行，可用异步。同一用户前一quote，withdraw次序得保证。方法1 withdraw检查refkey，如果不存在，则设定该key，给出status，该key设一个withraw key， 好让后到得quote找到，然后简单抛弃，留待以后处理。quote 检查key，如果存在，则是重复quote 或是withdraw所设。找到该withdraw key，设置该withdraw staus finished。这些动作使用lua做最好。方法2 withdraw插入后到match，先跑一遍，如果没找到，有可能是withdraw quote 跑到了前面，那么插入到一个队列。 每次quote到时，都检查一次。 方法2 在match中检查比较耗时。采用方法1
           //异步插入，检查 在callback中出错
           //exchange类， 不同用户基本上不会冲突，可在主线程运行，
           //在contractnote note可并行，异步
           //redis 的集群可按user来设置 ，note 进行记帐时候，会涉及到多个机器，多个机器之间怎么保证同步
        
           //关键是连接mongodb，couchdb等外部资源的客户端，要有好的异步设计。才能在应用上提高吞吐
           //node.js js 有好的异步设计，vert.x呢？
           //node.js 对外部资源的异步使用封装得怎样？vert.x呢？
           //eventbus内部使用无锁队列，使用event bus，回调函数插入event(成功或失败)到event bus，
           //应用程序只需要处理event bus
           //event switch类要预先定制好多个callback事件，尤其是web应用相关的
           //web服务器采用的fastcgi接口如果异步实现，效率能提高多少
           
           ReaderWriterQueue<message_t> * main_msg_queue = (ReaderWriterQueue<message_t> *)stream->data;
        main_msg_queue->enqueue(msg);
    }while(0);
    free((void *)buf.base);
    uv_close((uv_handle_t*) stream, on_client_close);
}


void on_client_connection(uv_stream_t *server, int status) {
    if (status == -1) {
        return;
    }
    
    uv_tcp_t *client = (uv_tcp_t*) malloc(sizeof(uv_tcp_t));
    uv_tcp_init(loop, client);

    client->data = server->data;
    if (uv_accept(server, (uv_stream_t*) client) == 0) {
        uv_read_start((uv_stream_t*) client, alloc_message_buffer, on_message_received);
    }else {
        uv_close((uv_handle_t*) client, on_client_close);
    }
}


void routine_quote_cb(uv_timer_t *handle, int){
    publisher.publish(Singleton<RoutineQuotation>::instance());
}

template<> MessageProcessorMap * Singleton<MessageProcessorMap, 1>::_instance = NULL;
           
int mainloop(int timeout, const string & host, int port, int port2
                    ,const string & publish_host, int publish_port
                    ,ReaderWriterQueue<message_t> * main_match_msg_queue
                    ,ReaderWriterQueue<message_t> * main_io_msg_queue
                    ,ReaderWriterQueue<message_t> * match_msg_queue
                    ,ReaderWriterQueue<message_t> * io_msg_quque){
    
    loop = uv_loop_new();

    uv_tcp_t server;
    uv_tcp_init(loop, &server);
    server->data = (void *)main_io_msg_queue;
    
    struct sockaddr_in bind_addr = uv_ip4_addr(host.c_str(), port);
    uv_tcp_bind(&server, bind_addr);
    int r = uv_listen((uv_stream_t*) &server, 128, on_client_connection);
    if (r) {
        fprintf(stderr, "Listen error %s\n", uv_err_name(uv_last_error(loop)));
        return 1;
    }
    
    RedisPublisher  publisher;
    publisher.connect("localhost", 6379);
    redisLibuvAttach(publisher.getContext(),loop);

    uv_timer_t timer_req;
    uv_timer_init(loop, &timer_req);
    uv_timer_start(&timer_req, routine_quote_cb, timeout, timeout);
    
    int len = 2;
    ReaderWriterQueue<message_t> * inqueue[len];
    inqueue[0] = main_match_msg_queue;
    inqueue[1] = main_io_msg_queue;
    message_t msg;
    list<message_t> out_msg_list;
    extern bool g_run;
    while(g_run){
        for(int i=0; i++; i<len){
            if(inqueue[i].try_dequeue(msg)){
                switch(msg.quote.status){
                    case STATUS_NEW:
                        if(msg.quote.msg_type == ){
                            
                        }else{
                            
                        }
                        io_msg_quque.enqueue(msg);
                        break;
                    case STATUS_ACCEPTED:
                        match_msg_quque.enqueue(msg);
                        break;
                    case STATUS_PROCESSED:
                        io_msg_quque.enqueue(msg);
                        break;
                    case STATUS_FINISHED:
                        Singleton<RoutineQuation>::instance().update(&msg);
                        publisher.update(&msg);
                        break;
                    default:
                        break;
            }
        }
        
        uv_run(loop, UV_RUN_NOWAIT);
    }

    return 0;
}<file_sep>/******************************************************************* 
 * C file generated by Protoc for Embedded C.                      *
 * Version 1.0M4 (2013-03-31)                                      *
 *                                                                 *
 * Copyright (c) 2009-2013                                         *
 * Technische Universitaet Muenchen                                *
 * http://www4.in.tum.de/                                          *
 *                                                                 *
 * Source : message.proto
 *                                                                 *
 * Do not edit.                                                    *
 *******************************************************************/
 
#include "Message.h"

int _memcmp(const void *p1, const void *p2, unsigned int size) {
    unsigned int i;
    for(i = 0; i < size; ++ i) {
        if(*((char*)p1 + i) > *((char*)p2 + i))
            return 1;
        if(*((char*)p1 + i) < *((char*)p2 + i))
            return -1;
    }
    return 0;
} 
 
void _memset(void *msg_ptr, char init_val, unsigned int size) {
    unsigned int i;
    for(i = 0; i < size; ++ i)
        *((char*)msg_ptr + i) = init_val;
}

int varint_packed_size(unsigned long value) {
    if ((value & (0xffffffff <<  7)) == 0) return 1;
    if ((value & (0xffffffff << 14)) == 0) return 2;
    if ((value & (0xffffffff << 21)) == 0) return 3;
    if ((value & (0xffffffff << 28)) == 0) return 4;
    return 5;  
}

int write_raw_byte(char value, void *_buffer, int offset) {
    *((char *)_buffer + offset) = value;
    return ++offset;
}

/** Write a little-endian 32-bit integer. */
int write_raw_little_endian32(unsigned long value, void *_buffer, int offset) {
    offset = write_raw_byte((char)((value      ) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >>  8) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 16) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 24) & 0xFF), _buffer, offset);
    
    return offset;
}

/** Write a little-endian 64-bit integer. */
int write_raw_little_endian64(unsigned long long value, void *_buffer, int offset) {
    offset = write_raw_byte((char)((value      ) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >>  8) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 16) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 24) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 32) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 40) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 48) & 0xFF), _buffer, offset);
    offset = write_raw_byte((char)((value >> 56) & 0xFF), _buffer, offset);
    
    return offset;
}

int write_raw_varint32(unsigned long value, void *_buffer, int offset) {
    while (1) {
        if ((value & ~0x7F) == 0) {
            offset = write_raw_byte((char)value, _buffer, offset);
            return offset;
        } else {
            offset = write_raw_byte((char)((value & 0x7F) | 0x80), _buffer, offset);
            value = value >> 7;
        }
    }
    return offset;
}

int write_raw_varint64(unsigned long long value, void *_buffer, int offset) {
    while (1) {
        if ((value & ~0x7FL) == 0) {
            offset = write_raw_byte((char)value, _buffer, offset);
            return offset;
        } else {
            offset = write_raw_byte((char)((value & 0x7F) | 0x80), _buffer, offset);
            value = value >> 7;
        }
    }
    return offset;
}

int write_raw_bytes(char *bytes, int bytes_size, void *_buffer, int offset) {
    int i; 
    for(i = 0; i < bytes_size; ++ i) {
        offset = write_raw_byte((char)*(bytes + i), _buffer, offset);
    }
    
    return offset;   
}

unsigned long encode_zig_zag32(signed long n) {
    /* Note:  the right-shift must be arithmetic. */
    return (n << 1) ^ (n >> 31);
}

unsigned long long encode_zig_zag64(signed long long n) {
    /* Note:  the right-shift must be arithmetic. */
    return (n << 1) ^ (n >> 63);
} 

signed long decode_zig_zag32(unsigned long n) {
    return (n >> 1) ^ -(n & 1);
}

signed long long decode_zig_zag64(unsigned long long n) {
    return (n >> 1) ^ -(n & 1);
}

int read_raw_byte(char *tag, void *_buffer, int offset) {
    *tag = *((char *) _buffer + offset);
    
    return ++offset;
}

/** Read a 32-bit little-endian integer from the stream. */
int read_raw_little_endian32(unsigned long *tag, void *_buffer, int offset) {
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b1 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b2 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b3 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b4 = (char) *tag;
    
    *tag = (((unsigned long)b1 & 0xff)      ) |
           (((unsigned long)b2 & 0xff) <<  8) |
           (((unsigned long)b3 & 0xff) << 16) |
           (((unsigned long)b4 & 0xff) << 24);
           
    return offset;
}

/** Read a 64-bit little-endian integer from the stream. */
int read_raw_little_endian64(unsigned long long *tag, void *_buffer, int offset) {
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b1 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b2 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b3 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b4 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b5 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b6 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b7 = (char) *tag;
    offset = read_raw_byte((char *)tag, _buffer, offset);
    char b8 = (char) *tag;
    
    *tag = (((unsigned long long)b1 & 0xff)      ) |
           (((unsigned long long)b2 & 0xff) <<  8) |
           (((unsigned long long)b3 & 0xff) << 16) |
           (((unsigned long long)b4 & 0xff) << 24) |
           (((unsigned long long)b5 & 0xff) << 32) |
           (((unsigned long long)b6 & 0xff) << 40) |
           (((unsigned long long)b7 & 0xff) << 48) |
           (((unsigned long long)b8 & 0xff) << 56);
           
    return offset;
}

int read_raw_varint32(unsigned long *tag, void *_buffer, int offset) {
    signed char result;
    
    offset = read_raw_byte((char *)&result, _buffer, offset);
    if (result >= 0) {
        *tag = result;
        return offset;
    }
    *tag = result & 0x7f;
    offset = read_raw_byte((char *)&result, _buffer, offset);
    if (result >= 0) {
        *tag |= result << 7;
    } else {
        *tag |= (result & 0x7f) << 7;
        offset = read_raw_byte((char *)&result, _buffer, offset);
        if (result >= 0) {
            *tag |= result << 14;
        } else {
            *tag |= (result & 0x7f) << 14;
            offset = read_raw_byte((char *)&result, _buffer, offset);
            if (result >= 0) {
                *tag |= ((unsigned long)result) << 21;
            } else {
                *tag |= (((unsigned long)result) & 0x7f) << 21;
                offset = read_raw_byte((char *)&result, _buffer, offset);
                *tag |= ((unsigned long)result) << 28;
                if (result < 0) {
                    /* Discard upper 32 bits. */
                    int i;
                    for (i = 0; i < 5; ++ i) {
                        offset = read_raw_byte((char *)&result, _buffer, offset);
                        if (result >= 0) {
                            return offset;
                        }
                    }
                    /* Invalid state. */
                }
            }
        }
    }
    return offset;
}

int read_raw_varint64(unsigned long long *tag, void *_buffer, int offset) {
    short shift = 0;
    signed char b;
    *tag = 0;
    while (shift < 64) {
        offset = read_raw_byte((char *)&b, _buffer, offset);
        *tag |= (unsigned long long)(b & 0x7F) << shift;
        if ((b & 0x80) == 0) {
            return offset;
        }
        shift += 7;
    }
    /* return error code. */
    return -1;
}

int can_read_raw_varint32(void *_buffer, int offset, int length) {
    signed char c;
    
    /* Bound length to valid range [0..5]. */
    if (length < 0) length = 0; else
    if (length > 5) length = 5;
    
    while (length > 0) {
        offset = read_raw_byte((char *)&c, _buffer, offset);
        if (c >= 0) {
            return 1; /* Can read (1 == true). */
        }
        length--;
    }
    
    return 0; /* Cannot read (0 == false). */
}

int can_read_raw_varint64(void *_buffer, int offset, int length) {
    signed char c;
    
    /* Bound length to valid range [0..5]. */
    if (length < 0) length = 0; else
    if (length > 10) length = 10;
    
    while (length > 0) {
        offset = read_raw_byte((char *)&c, _buffer, offset);
        if (c >= 0) {
            return 1; /* Can read (1 == true). */
        }
        length--;
    }
    
    return 0; /* Cannot read (0 == false). */
}

int Message_can_read_delimited_from(void *_buffer, int offset, unsigned int length) {
    unsigned long size;
    int payload_offset;

    if (length <= 0) return 0; /* Cannot read from empty or invalid message. */

    if (!can_read_raw_varint32(_buffer, offset, length)) {
        return 0; /* Could not even read the preceding size as varint32. */
    }

    payload_offset = read_raw_varint32(&size, _buffer, offset);
    length = length - (payload_offset - offset);

    return (length >= size) ? 1 : 0;
}

unsigned long Message_get_delimited_size(void *_buffer, int offset) {
    unsigned long size = 0;
    int old_offset = offset;
    
    offset = read_raw_varint32(&size, _buffer, offset);
    
    return size + offset - old_offset;
}

/*******************************************************************
* Enumeration: Message.proto, line 26
*******************************************************************/
int message_type_t_write_with_tag(enum message_type_t *_message_type_t, void *_buffer, int offset, int tag) {
    /* Write tag.*/
    offset = write_raw_varint32((tag<<3)+0, _buffer, offset);
    /* Write content.*/
    offset = write_raw_varint32(*_message_type_t, _buffer, offset);
    
    return offset;
}

/*******************************************************************
* Enumeration: Message.proto, line 17
*******************************************************************/
int bill_status_t_write_with_tag(enum bill_status_t *_bill_status_t, void *_buffer, int offset, int tag) {
    /* Write tag.*/
    offset = write_raw_varint32((tag<<3)+0, _buffer, offset);
    /* Write content.*/
    offset = write_raw_varint32(*_bill_status_t, _buffer, offset);
    
    return offset;
}

/*******************************************************************
* Enumeration: Message.proto, line 5
*******************************************************************/
int security_bill_t_write_with_tag(enum security_bill_t *_security_bill_t, void *_buffer, int offset, int tag) {
    /* Write tag.*/
    offset = write_raw_varint32((tag<<3)+0, _buffer, offset);
    /* Write content.*/
    offset = write_raw_varint32(*_security_bill_t, _buffer, offset);
    
    return offset;
}


/*******************************************************************
 * Message: Message.proto, line 35
 *******************************************************************/

void SecurityQuote_clear(struct SecurityQuote *_SecurityQuote) {
	_memset(_SecurityQuote, 0, sizeof(struct SecurityQuote));
}

void SecurityQuote_init_optional_attributes(struct SecurityQuote *_SecurityQuote) {
}

int SecurityQuote_is_default_message(struct SecurityQuote *_SecurityQuote) {
    return _SecurityQuote->msg_type == 0
    
     && _SecurityQuote->billType == 0
    
     && _SecurityQuote->billId == 0
    
     && _SecurityQuote->occurTime == 0
    
     && _SecurityQuote->status == 0
    
     && _SecurityQuote->code == 0
    
     && _SecurityQuote->price == 0
    
     && _SecurityQuote->quality == 0
    
     && _SecurityQuote->_guaranty == 0
    
     && _SecurityQuote->_client_len == 0
    ;
}

int SecurityQuote_write(struct SecurityQuote *_SecurityQuote, void *_buffer, int offset) {
	/* Write content of each message element.*/
	offset = message_type_t_write_with_tag(&_SecurityQuote->msg_type, _buffer, offset, 1);
	
	offset = security_bill_t_write_with_tag(&_SecurityQuote->billType, _buffer, offset, 2);
	
	offset = write_raw_varint32((3<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->billId, _buffer, offset);
	
	offset = write_raw_varint32((4<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->occurTime, _buffer, offset);
	
	offset = bill_status_t_write_with_tag(&_SecurityQuote->status, _buffer, offset, 5);
	
	offset = write_raw_varint32((6<<3)+0, _buffer, offset);
	offset = write_raw_varint64(_SecurityQuote->code, _buffer, offset);
	
	offset = write_raw_varint32((7<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->price, _buffer, offset);
	
	offset = write_raw_varint32((8<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->quality, _buffer, offset);
	
	offset = write_raw_varint32((9<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->_guaranty, _buffer, offset);
	
	offset = write_raw_varint32((10<<3)+2, _buffer, offset);
	offset = write_raw_varint32(_SecurityQuote->_client_len, _buffer, offset);
	offset = write_raw_bytes(_SecurityQuote->client, _SecurityQuote->_client_len, _buffer, offset);
	
	return offset;
}

int SecurityQuote_write_with_tag(struct SecurityQuote *_SecurityQuote, void *_buffer, int offset, int tag) {
	/* Write tag.*/
	offset = write_raw_varint32((tag<<3)+2, _buffer, offset);
	/* Write content.*/
	offset = SecurityQuote_write_delimited_to(_SecurityQuote, _buffer, offset);
	
	return offset;
}

int SecurityQuote_write_delimited_to(struct SecurityQuote *_SecurityQuote, void *_buffer, int offset) {
	int i, shift, new_offset, size;
	
	new_offset = SecurityQuote_write(_SecurityQuote, _buffer, offset);
	size = new_offset - offset;
	shift = (size > 127) ? 2 : 1;
	for (i = new_offset - 1; i >= offset; -- i)
	    *((char *)_buffer + i + shift) = *((char *)_buffer + i);
	
	write_raw_varint32((unsigned long) size, _buffer, offset);         
	    
	return new_offset + shift;
}

int SecurityQuote_read(void *_buffer, struct SecurityQuote *_SecurityQuote, int offset, int limit) {
	unsigned int i = 0;
	unsigned long long value = i;
	unsigned long tag = value;
	
	/* Reset all attributes to 0 in advance. */
	SecurityQuote_clear(_SecurityQuote);
	/* Assign the optional attributes. */
	SecurityQuote_init_optional_attributes(_SecurityQuote);
	
	/* Read/interpret all attributes from buffer offset until upper limit is reached. */
	while(offset < limit) {
	    offset = read_raw_varint32(&tag, _buffer, offset);
		tag = tag>>3;
	    switch(tag){
	        /* tag of: _SecurityQuote.msg_type */
	        case 1 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->msg_type = tag;
	        	break;
	        /* tag of: _SecurityQuote.billType */
	        case 2 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->billType = tag;
	        	break;
	        /* tag of: _SecurityQuote.billId */
	        case 3 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->billId = tag;
	        	break;
	        /* tag of: _SecurityQuote.occurTime */
	        case 4 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->occurTime = tag;
	        	break;
	        /* tag of: _SecurityQuote._status */
	        case 5 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->status = tag;
	        	break;
	        /* tag of: _SecurityQuote._code */
	        case 6 :
	        	offset = read_raw_varint64(&value, _buffer, offset);
	        	_SecurityQuote->code = value;
	        	break;
	        /* tag of: _SecurityQuote._price */
	        case 7 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->price = tag;
	        	break;
	        /* tag of: _SecurityQuote._quality */
	        case 8 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->quality = tag;
	        	break;
	        /* tag of: _SecurityQuote._guaranty */
	        case 9 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->_guaranty = tag;
	        	break;
	        /* tag of: _SecurityQuote._client */
	        case 10 :
	        	/* Re-use 'tag' to store string length. */
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_SecurityQuote->_client_len = tag;
	        	for(i = 0; i < tag; ++ i) 
	        	    offset = read_raw_byte((_SecurityQuote->client + i), _buffer, offset);
	        	break;
	    }
	}
	
	return offset;
}

int SecurityQuote_read_delimited_from(void *_buffer, struct SecurityQuote *_SecurityQuote, int offset) {
	unsigned long size;
	
	offset = read_raw_varint32(&size, _buffer, offset);
	SecurityQuote_read(_buffer, _SecurityQuote, offset, size + offset);
	
	return offset + size;
}
/*******************************************************************
 * Message: Message.proto, line 49
 *******************************************************************/

void WithdrawQuote_clear(struct WithdrawQuote *_WithdrawQuote) {
	_memset(_WithdrawQuote, 0, sizeof(struct WithdrawQuote));
}

void WithdrawQuote_init_optional_attributes(struct WithdrawQuote *_WithdrawQuote) {
}

int WithdrawQuote_is_default_message(struct WithdrawQuote *_WithdrawQuote) {
    return _WithdrawQuote->msg_type == 0
    
     && _WithdrawQuote->billType == 0
    
     && _WithdrawQuote->billId == 0
    
     && _WithdrawQuote->occurTime == 0
    
     && _WithdrawQuote->status == 0
    
     && _WithdrawQuote->code == 0
    
     && _WithdrawQuote->refBillId == 0
    
     && _WithdrawQuote->_client_len == 0
    ;
}

int WithdrawQuote_write(struct WithdrawQuote *_WithdrawQuote, void *_buffer, int offset) {
	/* Write content of each message element.*/
	offset = message_type_t_write_with_tag(&_WithdrawQuote->msg_type, _buffer, offset, 1);
	
	offset = security_bill_t_write_with_tag(&_WithdrawQuote->billType, _buffer, offset, 2);
	
	offset = write_raw_varint32((3<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_WithdrawQuote->billId, _buffer, offset);
	
	offset = write_raw_varint32((4<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_WithdrawQuote->occurTime, _buffer, offset);
	
	offset = bill_status_t_write_with_tag(&_WithdrawQuote->status, _buffer, offset, 5);
	
	offset = write_raw_varint32((6<<3)+0, _buffer, offset);
	offset = write_raw_varint64(_WithdrawQuote->code, _buffer, offset);
	
	offset = write_raw_varint32((7<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_WithdrawQuote->refBillId, _buffer, offset);
	
	offset = write_raw_varint32((8<<3)+2, _buffer, offset);
	offset = write_raw_varint32(_WithdrawQuote->_client_len, _buffer, offset);
	offset = write_raw_bytes(_WithdrawQuote->client, _WithdrawQuote->_client_len, _buffer, offset);
	
	return offset;
}

int WithdrawQuote_write_with_tag(struct WithdrawQuote *_WithdrawQuote, void *_buffer, int offset, int tag) {
	/* Write tag.*/
	offset = write_raw_varint32((tag<<3)+2, _buffer, offset);
	/* Write content.*/
	offset = WithdrawQuote_write_delimited_to(_WithdrawQuote, _buffer, offset);
	
	return offset;
}

int WithdrawQuote_write_delimited_to(struct WithdrawQuote *_WithdrawQuote, void *_buffer, int offset) {
	int i, shift, new_offset, size;
	
	new_offset = WithdrawQuote_write(_WithdrawQuote, _buffer, offset);
	size = new_offset - offset;
	shift = (size > 127) ? 2 : 1;
	for (i = new_offset - 1; i >= offset; -- i)
	    *((char *)_buffer + i + shift) = *((char *)_buffer + i);
	
	write_raw_varint32((unsigned long) size, _buffer, offset);         
	    
	return new_offset + shift;
}

int WithdrawQuote_read(void *_buffer, struct WithdrawQuote *_WithdrawQuote, int offset, int limit) {
	unsigned int i = 0;
	unsigned long long value = i;
	unsigned long tag = value;
	
	/* Reset all attributes to 0 in advance. */
	WithdrawQuote_clear(_WithdrawQuote);
	/* Assign the optional attributes. */
	WithdrawQuote_init_optional_attributes(_WithdrawQuote);
	
	/* Read/interpret all attributes from buffer offset until upper limit is reached. */
	while(offset < limit) {
	    offset = read_raw_varint32(&tag, _buffer, offset);
		tag = tag>>3;
	    switch(tag){
	        /* tag of: _WithdrawQuote.msg_type */
	        case 1 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->msg_type = tag;
	        	break;
	        /* tag of: _WithdrawQuote.billType */
	        case 2 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->billType = tag;
	        	break;
	        /* tag of: _WithdrawQuote.billId */
	        case 3 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->billId = tag;
	        	break;
	        /* tag of: _WithdrawQuote.occurTime */
	        case 4 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->occurTime = tag;
	        	break;
	        /* tag of: _WithdrawQuote._status */
	        case 5 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->status = tag;
	        	break;
	        /* tag of: _WithdrawQuote._code */
	        case 6 :
	        	offset = read_raw_varint64(&value, _buffer, offset);
	        	_WithdrawQuote->code = value;
	        	break;
	        /* tag of: _WithdrawQuote._refBillId */
	        case 7 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->refBillId = tag;
	        	break;
	        /* tag of: _WithdrawQuote._client */
	        case 8 :
	        	/* Re-use 'tag' to store string length. */
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_WithdrawQuote->_client_len = tag;
	        	for(i = 0; i < tag; ++ i) 
	        	    offset = read_raw_byte((_WithdrawQuote->client + i), _buffer, offset);
	        	break;
	    }
	}
	
	return offset;
}

int WithdrawQuote_read_delimited_from(void *_buffer, struct WithdrawQuote *_WithdrawQuote, int offset) {
	unsigned long size;
	
	offset = read_raw_varint32(&size, _buffer, offset);
	WithdrawQuote_read(_buffer, _WithdrawQuote, offset, size + offset);
	
	return offset + size;
}
/*******************************************************************
 * Message: Message.proto, line 61
 *******************************************************************/

void ContractNote_clear(struct ContractNote *_ContractNote) {
	_memset(_ContractNote, 0, sizeof(struct ContractNote));
}

void ContractNote_init_optional_attributes(struct ContractNote *_ContractNote) {
}

int ContractNote_is_default_message(struct ContractNote *_ContractNote) {
    return _ContractNote->msg_type == 0
    
     && _ContractNote->billType == 0
    
     && _ContractNote->billId == 0
    
     && _ContractNote->occurTime == 0
    
     && _ContractNote->status == 0
    
     && _ContractNote->code == 0
    
     && _ContractNote->price == 0
    
     && _ContractNote->quality == 0
    
     && _ContractNote->sourceBillId == 0
    
     && _ContractNote->peerBillId == 0
    
     && _ContractNote->_buyer_len == 0
    
     && _ContractNote->_seller_len == 0
    ;
}

int ContractNote_write(struct ContractNote *_ContractNote, void *_buffer, int offset) {
	/* Write content of each message element.*/
	offset = message_type_t_write_with_tag(&_ContractNote->msg_type, _buffer, offset, 1);
	
	offset = security_bill_t_write_with_tag(&_ContractNote->billType, _buffer, offset, 2);
	
	offset = write_raw_varint32((3<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->billId, _buffer, offset);
	
	offset = write_raw_varint32((4<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->occurTime, _buffer, offset);
	
	offset = bill_status_t_write_with_tag(&_ContractNote->status, _buffer, offset, 5);
	
	offset = write_raw_varint32((6<<3)+0, _buffer, offset);
	offset = write_raw_varint64(_ContractNote->code, _buffer, offset);
	
	offset = write_raw_varint32((7<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->price, _buffer, offset);
	
	offset = write_raw_varint32((8<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->quality, _buffer, offset);
	
	offset = write_raw_varint32((9<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->sourceBillId, _buffer, offset);
	
	offset = write_raw_varint32((10<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->peerBillId, _buffer, offset);
	
	offset = write_raw_varint32((11<<3)+2, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->_buyer_len, _buffer, offset);
	offset = write_raw_bytes(_ContractNote->buyer, _ContractNote->_buyer_len, _buffer, offset);
	
	offset = write_raw_varint32((12<<3)+2, _buffer, offset);
	offset = write_raw_varint32(_ContractNote->_seller_len, _buffer, offset);
	offset = write_raw_bytes(_ContractNote->seller, _ContractNote->_seller_len, _buffer, offset);
	
	return offset;
}

int ContractNote_write_with_tag(struct ContractNote *_ContractNote, void *_buffer, int offset, int tag) {
	/* Write tag.*/
	offset = write_raw_varint32((tag<<3)+2, _buffer, offset);
	/* Write content.*/
	offset = ContractNote_write_delimited_to(_ContractNote, _buffer, offset);
	
	return offset;
}

int ContractNote_write_delimited_to(struct ContractNote *_ContractNote, void *_buffer, int offset) {
	int i, shift, new_offset, size;
	
	new_offset = ContractNote_write(_ContractNote, _buffer, offset);
	size = new_offset - offset;
	shift = (size > 127) ? 2 : 1;
	for (i = new_offset - 1; i >= offset; -- i)
	    *((char *)_buffer + i + shift) = *((char *)_buffer + i);
	
	write_raw_varint32((unsigned long) size, _buffer, offset);         
	    
	return new_offset + shift;
}

int ContractNote_read(void *_buffer, struct ContractNote *_ContractNote, int offset, int limit) {
	unsigned int i = 0;
	unsigned long long value = i;
	unsigned long tag = value;
	
	/* Reset all attributes to 0 in advance. */
	ContractNote_clear(_ContractNote);
	/* Assign the optional attributes. */
	ContractNote_init_optional_attributes(_ContractNote);
	
	/* Read/interpret all attributes from buffer offset until upper limit is reached. */
	while(offset < limit) {
	    offset = read_raw_varint32(&tag, _buffer, offset);
		tag = tag>>3;
	    switch(tag){
	        /* tag of: _ContractNote.msg_type */
	        case 1 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->msg_type = tag;
	        	break;
	        /* tag of: _ContractNote.billType */
	        case 2 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->billType = tag;
	        	break;
	        /* tag of: _ContractNote.billId */
	        case 3 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->billId = tag;
	        	break;
	        /* tag of: _ContractNote.occurTime */
	        case 4 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->occurTime = tag;
	        	break;
	        /* tag of: _ContractNote._status */
	        case 5 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->status = tag;
	        	break;
	        /* tag of: _ContractNote._code */
	        case 6 :
	        	offset = read_raw_varint64(&value, _buffer, offset);
	        	_ContractNote->code = value;
	        	break;
	        /* tag of: _ContractNote._price */
	        case 7 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->price = tag;
	        	break;
	        /* tag of: _ContractNote._quality */
	        case 8 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->quality = tag;
	        	break;
	        /* tag of: _ContractNote._sourceBillId */
	        case 9 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->sourceBillId = tag;
	        	break;
	        /* tag of: _ContractNote._peerBillId */
	        case 10 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->peerBillId = tag;
	        	break;
	        /* tag of: _ContractNote._buyer */
	        case 11 :
	        	/* Re-use 'tag' to store string length. */
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->_buyer_len = tag;
	        	for(i = 0; i < tag; ++ i) 
	        	    offset = read_raw_byte((_ContractNote->buyer + i), _buffer, offset);
	        	break;
	        /* tag of: _ContractNote._seller */
	        case 12 :
	        	/* Re-use 'tag' to store string length. */
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_ContractNote->_seller_len = tag;
	        	for(i = 0; i < tag; ++ i) 
	        	    offset = read_raw_byte((_ContractNote->seller + i), _buffer, offset);
	        	break;
	    }
	}
	
	return offset;
}

int ContractNote_read_delimited_from(void *_buffer, struct ContractNote *_ContractNote, int offset) {
	unsigned long size;
	
	offset = read_raw_varint32(&size, _buffer, offset);
	ContractNote_read(_buffer, _ContractNote, offset, size + offset);
	
	return offset + size;
}
/*******************************************************************
 * Message: Message.proto, line 78
 *******************************************************************/

void AccountExchangeNote_clear(struct AccountExchangeNote *_AccountExchangeNote) {
	_memset(_AccountExchangeNote, 0, sizeof(struct AccountExchangeNote));
}

void AccountExchangeNote_init_optional_attributes(struct AccountExchangeNote *_AccountExchangeNote) {
}

int AccountExchangeNote_is_default_message(struct AccountExchangeNote *_AccountExchangeNote) {
    return _AccountExchangeNote->msg_type == 0
    
     && _AccountExchangeNote->billType == 0
    
     && _AccountExchangeNote->billId == 0
    
     && _AccountExchangeNote->occurTime == 0
    
     && _AccountExchangeNote->status == 0
    
     && _AccountExchangeNote->code == 0
    
     && _AccountExchangeNote->quality == 0
    
     && _AccountExchangeNote->_client_len == 0
    ;
}

int AccountExchangeNote_write(struct AccountExchangeNote *_AccountExchangeNote, void *_buffer, int offset) {
	/* Write content of each message element.*/
	offset = message_type_t_write_with_tag(&_AccountExchangeNote->msg_type, _buffer, offset, 1);
	
	offset = security_bill_t_write_with_tag(&_AccountExchangeNote->billType, _buffer, offset, 2);
	
	offset = write_raw_varint32((3<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_AccountExchangeNote->billId, _buffer, offset);
	
	offset = write_raw_varint32((4<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_AccountExchangeNote->occurTime, _buffer, offset);
	
	offset = bill_status_t_write_with_tag(&_AccountExchangeNote->status, _buffer, offset, 5);
	
	offset = write_raw_varint32((6<<3)+0, _buffer, offset);
	offset = write_raw_varint64(_AccountExchangeNote->code, _buffer, offset);
	
	offset = write_raw_varint32((7<<3)+0, _buffer, offset);
	offset = write_raw_varint32(_AccountExchangeNote->quality, _buffer, offset);
	
	offset = write_raw_varint32((8<<3)+2, _buffer, offset);
	offset = write_raw_varint32(_AccountExchangeNote->_client_len, _buffer, offset);
	offset = write_raw_bytes(_AccountExchangeNote->client, _AccountExchangeNote->_client_len, _buffer, offset);
	
	return offset;
}

int AccountExchangeNote_write_with_tag(struct AccountExchangeNote *_AccountExchangeNote, void *_buffer, int offset, int tag) {
	/* Write tag.*/
	offset = write_raw_varint32((tag<<3)+2, _buffer, offset);
	/* Write content.*/
	offset = AccountExchangeNote_write_delimited_to(_AccountExchangeNote, _buffer, offset);
	
	return offset;
}

int AccountExchangeNote_write_delimited_to(struct AccountExchangeNote *_AccountExchangeNote, void *_buffer, int offset) {
	int i, shift, new_offset, size;
	
	new_offset = AccountExchangeNote_write(_AccountExchangeNote, _buffer, offset);
	size = new_offset - offset;
	shift = (size > 127) ? 2 : 1;
	for (i = new_offset - 1; i >= offset; -- i)
	    *((char *)_buffer + i + shift) = *((char *)_buffer + i);
	
	write_raw_varint32((unsigned long) size, _buffer, offset);         
	    
	return new_offset + shift;
}

int AccountExchangeNote_read(void *_buffer, struct AccountExchangeNote *_AccountExchangeNote, int offset, int limit) {
	unsigned int i = 0;
	unsigned long long value = i;
	unsigned long tag = value;
	
	/* Reset all attributes to 0 in advance. */
	AccountExchangeNote_clear(_AccountExchangeNote);
	/* Assign the optional attributes. */
	AccountExchangeNote_init_optional_attributes(_AccountExchangeNote);
	
	/* Read/interpret all attributes from buffer offset until upper limit is reached. */
	while(offset < limit) {
	    offset = read_raw_varint32(&tag, _buffer, offset);
		tag = tag>>3;
	    switch(tag){
	        /* tag of: _AccountExchangeNote.msg_type */
	        case 1 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->msg_type = tag;
	        	break;
	        /* tag of: _AccountExchangeNote.billType */
	        case 2 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->billType = tag;
	        	break;
	        /* tag of: _AccountExchangeNote.billId */
	        case 3 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->billId = tag;
	        	break;
	        /* tag of: _AccountExchangeNote.occurTime */
	        case 4 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->occurTime = tag;
	        	break;
	        /* tag of: _AccountExchangeNote._status */
	        case 5 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->status = tag;
	        	break;
	        /* tag of: _AccountExchangeNote._code */
	        case 6 :
	        	offset = read_raw_varint64(&value, _buffer, offset);
	        	_AccountExchangeNote->code = value;
	        	break;
	        /* tag of: _AccountExchangeNote._quality */
	        case 7 :
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->quality = tag;
	        	break;
	        /* tag of: _AccountExchangeNote._client */
	        case 8 :
	        	/* Re-use 'tag' to store string length. */
	        	offset = read_raw_varint32(&tag, _buffer, offset);
	        	_AccountExchangeNote->_client_len = tag;
	        	for(i = 0; i < tag; ++ i) 
	        	    offset = read_raw_byte((_AccountExchangeNote->client + i), _buffer, offset);
	        	break;
	    }
	}
	
	return offset;
}

int AccountExchangeNote_read_delimited_from(void *_buffer, struct AccountExchangeNote *_AccountExchangeNote, int offset) {
	unsigned long size;
	
	offset = read_raw_varint32(&size, _buffer, offset);
	AccountExchangeNote_read(_buffer, _AccountExchangeNote, offset, size + offset);
	
	return offset + size;
}
<file_sep>//
//  WithdrawProcessor.h
//  mycoin
//
//  Created by lx on 14-1-8.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef __mycoin__WithdrawProcessor__
#define __mycoin__WithdrawProcessor__

#include "MessageProcessor.h"

class WithdrawProcessor:public MessageProcessor{
protected:
    typedef int (*)(WithdrawQuote&) account_func_t;
    typedef int (*)(WithdrawQuote&) match_func_t;
    
    account_func_t accout;
    match_func_t match;
    
public:
    WithdrawProcessor(message_type msg_type, MessageProcessorMap* processorMap
                      , match_func_t match
                      , account_func_t accout
                     )
    :MessageProcessor(msg_type,processorMap){
        this.account = accont;
        this.match = match;
    }
    
    virtual int execute(message_t *msg,list<message_t> &out_msg_list){
        return execute(*((WithdrawQuote*)&msg),out_msg_list);
    }
    
    int execute(WithdrawQuote &quote,list<message_t> &out_msg_list){
        switch (quote.status) {
            case STATUS_NEW:
                return quote.status = STATUS_ACCEPTED;
            case STATUS_ACCEPTED:
                return match != NULL ? match(quote, out_msg_list) : STATUS_REJECTED;
            case STATUS_PROCESSED:
                return account != NULL ? account(quote, out_msg_list) : STATUS_REJECTED;
            default:
                break;
        }

        return STATUS_REJECTED;
    }
   
};

#endif /* defined(__mycoin__WithdrawAccount__) */
<file_sep>//
//  QuoteProcessorSetTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__MarketPriceStrategyTest__
#define __mycoin__MarketPriceStrategyTest__

#include "gtest/gtest.h"
#include "../MarketPriceStrategy.h"

#endif /* defined(__mycoin__QuoteProcessorSetTest__) */
<file_sep>//
//  MycoinApplication.cpp
//  mycoin-account
//
//  Created by lx on 13-12-25.
//  Copyright (c) 2013年 lx. All rights reserved.
//
#include <stdio.h>
#include <unistd.h>

#include <iostream>
#include <istream>
#include <ostream>
#include <string>
#include <Poco/Util/ServerApplication.h>
#include <uv.h>
#include "MycoinApplication.h"
#include "aroundMatch.h"
#include "thread_fn.h"
using namespace Poco;
using namespace Poco::Util;
using namespace std;

bool g_run = true;

int main(int argc, char** argv)
{
    MycoinApplication app;
    app.init(argc,argv);
    return app.run(argc, argv);
}


int mainloop(int timeout, const string & host, int port, int port2
             ,const string & publish_host, int publish_port
             ,ReaderWriterQueue<message_t> *main_msg_queue
             ,ReaderWriterQueue<message_t> *main_msg_queue2
             ,ReaderWriterQueue<message_t> * match_msg_queue
             ,ReaderWriterQueue<message_t> * io_msg_quque);

int MycoinApplication::main( const std::vector < std::string > & args){

    //loadConfiguration();
    LayeredConfiguration& conf = config();
    const string& host = "localhost"; //conf.getString("host");
    int port = 5000; //conf.getInt("quote_port");
    int port2 = 5001; //conf.getInt("fund_port");
   
    const string& publish_host = "localhost";//conf.getString("publish_host");
    int publish_port = 11211; //conf.getInt("publish_port");
    
    int timeout = 2000;//conf.getInt("quote");
    int quote_queue_length = 1024; //conf.getInt("quote_queue_length");
    int note_queue_length = 1024;//conf.getInt("note_queue_length");
    
    using namespace moodycamel;
#define CONTRANCT_NOTE_QUEUE_LENGTH 1024

    ReaderWriterQueue<message_t> main_msg_queue(quote_queue_length);
    ReaderWriterQueue<message_t> main_msg_queue2(quote_queue_length);
    ReaderWriterQueue<message_t> io_msg_quque(note_queue_length);
    ReaderWriterQueue<message_t> match_msg_queue(quote_queue_length);
    
    struct thread_context_t matchContext;
    matchContext.msgs = &match_msg_queue;
    matchContext.outs = &main_msg_queue;
    uv_thread_t match_id;
    uv_thread_create(&match_id, match_fn, &matchContext);
    uv_thread_join(&match_id);
    
    struct thread_context_t ioContext;
    ioContext.msgs = &io_msg_quque;
    ioContext.outs = &main_msg_queue2;
    uv_thread_t io_id;
    uv_thread_create(&io_id, io_fn, io_msg_quque, main_msg_queue);
    uv_thread_join(&io_id);
    

    return mainloop(timeout, host,  port, port2,  publish_host, publish_port, &notes, &main_msg_queue, &main_msg_queue2, &match_msg_queue, &io_msg_quque);
}

//routine quotation 日常行情
/*
 能否应用map reduce概念，可否嵌入lua，lua是否有足够数据结构来支撑
 */
//如果运行中多个事件，发生了关联，那么创建event source的snapshot救困难了。完成的事件之间的联系会生成一个图，
//当第一个事件产生的图不再生长时，也就是产生了相隔离的图之后，才能创建snapshot。恢复时，应把这些事件通通排除。
//但是排除这些事件之后，能否重演事件 CQRS？？无法保证的情况下，必须是整个系统snapshot，而不只是eventsource
//整个系统的snapshot必由多部分组成，多部分如何确保同步/同一? 是不是各部分都得模拟一个eventsource
//在一个不是24小时交易的系统中，可以每次启动做snapshot，那么也能做到从snapshot重演

<file_sep>//
//  QuoteWithDrawProcessor.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "QuoteWithDrawProcessorTest.h"
#include <typeinfo>

namespace {
    inline security_price_t process(SecurityQuote *quote, BuyQuoteMultiMap* buyQueue, SellQuoteMultiMap *sellQueue){
        
        SelfQuoteQueue *selfQueue = identify.getSelfQueue(buyQueue, sellQueue);
        for(typename SelfQuoteQueue::iterator iter = selfQueue->begin(); iter!=selfQueue->end(); iter++){
            if(quote->billId == iter->second.billId){
                finishQuote(quote);
                break;
            }
        }
        return 0;
    }
    
    class QuoteProcessorTest : public ::testing::Test {
        
    protected:
        // You can remove any or all of the following functions if its body
        // is empty.
        
        QuoteProcessorTest() {
            // You can do set-up work for each test here.
        }
        
        virtual ~QuoteProcessorTest() {
            // You can do clean-up work that doesn't throw exceptions here.
        }
        
        /*
         SetUpTestCase() 方法在第一个TestCase之前执行
         */
        static void SetUpTestCase() {
            code = random();
            QuoteQueue& quoteQueue = QuoteQueue::getInstance();
            sellQueue = &quoteQueue.getSellQuoteQueue(code);
            buyQueue = &quoteQueue.getBuyQuoteQueue(code);

            QuoteProcessorFactory& factory = QuoteProcessorFactory::getInstance();
            buyInLimitPriceProcessor = &factory.getQuoteProcessor(BUY_IN_LIMIT_PRICE);
            sellOutLimitPriceProcessor = &factory.getQuoteProcessor(SELL_OUT_LIMIT_PRICE);
            buyInMarketPriceProcessor = factory.getQuoteProcessor(BUY_IN_MARKET_PRICE);
            sellOutMarketPriceProcessor = factory.getQuoteProcessor(SELL_OUT_MARKET_PRICE);
            buyQuoteWithdrawProcessor = factory.getQuoteProcessor(BUY_WITHDRAW);
            sellQuoteWithdrawProcessor = factory.getQuoteProcessor(SELL_WITHDRAW);
  
        }
        /*
         TearDownTestCase() 方法在最后一个TestCase之后执行
         */
        static void TearDownTestCase() {
            QuoteQueue& quoteQueue = QuoteQueue::getInstance();
            quoteQueue.clearQueue();

        }

        
        
        // If the constructor and destructor are not enough for setting up
        // and cleaning up each test, you can define the following methods:
        //SetUp()方法在每个TestCase之前执行
        virtual void SetUp() {
            // Code here will be called immediately after the constructor (right
            // before each test).
            
        }
        
        //TearDown()方法在每个TestCase之后执行
        virtual void TearDown() {
            // Code here will be called immediately after each test (right
            // before the destructor).
            
            buyQueue.clear();
            sellQueue.clear();
            
        }
        
        // Objects declared here can be used by all tests in the test case.
        SellQuoteMultiMap * sellQueue;
        BuyQuoteMultiMap * buyQueue;
        security_code_t code;
        
        QuoteProcessor* buyInLimitPriceProcessor;
        QuoteProcessor* sellOutLimitPriceProcessor;
        QuoteProcessor* buyInMarketPriceProcessor;
        QuoteProcessor* sellOutMarketPriceProcessor;
        QuoteProcessor* buyQuoteWithdrawProcessor;
        QuoteProcessor* sellQuoteWithdrawProcessor;

    };

    
    TEST_F(QuoteProcessorTest, withdrawBuy) {
        
        SecurityQuote quote;
        quote.billId = random();
        quote.code = code;
        quote.billType = BUY_IN_LIMIT_PRICE;
        
        buyInLimitPriceProcessor.process(&quote, buyQueue, sellQueue);
        
        SecurityQuote quote2;
        quote2.billId = random();
        quote2.code = code;
        quote2.refBillId = quote.billId;
        quote2.billType = BUY_WITHDRAW;
        
        buyWithdrawProcessor.process(&quote, buyQueue, sellQueue );
        
        int count = 0;
        for (QuoteProcessor::iterator iter =buyWithdrawProcessor.notes_begin(); iter!= buyWithdrawProcessor.notes_end(); iter++) {
            if(iter.sourceBillId == quote.billId || iter.sourceBillId == quote2.billId){
                count++;
            }
        }
        
        ASSERT_EQ(count, 2);
        //同时判断是否finished单，即其余参数为０
        
        count = 0;
        for (BuyQuoteMuiltiMap::iterator iter = buyQueue.begin(); iter!= buyQueue.end(); iter++) {
            if(iter.billId == quote2.refBillId){
                count = 1;
                break;
            }
        }
        
        ASSERT_EQ(count, 0);
    }
    
    TEST_F(QuoteProcessorTest, withdrawSell) {
        
        SecurityQuote quote;
        quote.billId = random();
        quote.code = code;
        quote.billType = SELL_OUT_LIMIT_PRICE;
        
        buyInLimitPriceProcessor.process(&quote, buyQueue, sellQueue);
        
        SecurityQuote quote2;
        quote2.billId = random();
        quote2.code = code;
        quote2.refBillId = quote.billId;
        quote2.billType = BUY_WITHDRAW;
        
        buyWithdrawProcessor.process(&quote, buyQueue, sellQueue );
        
        int count = 0;
        for (QuoteProcessor::iterator iter =buyWithdrawProcessor.notes_begin(); iter!= buyWithdrawProcessor.notes_end(); iter++) {
            if(iter.sourceBillId == quote.billId || iter.sourceBillId == quote2.billId){
                count++;
            }
        }
        
        ASSERT_EQ(count, 2);
        //同时判断是否finished单，即其余参数为０
        
        count = 0;
        for (BuyQuoteMuiltiMap::iterator iter = buyQueue.begin(); iter!= buyQueue.end(); iter++) {
            if(iter.billId == quote2.refBillId){
                count = 1;
                break;
            }
        }
        
        ASSERT_EQ(count, 0);
    }

    
}  // namespace<file_sep>//
//  Account.h
//  mycoin
//
//  Created by lx on 13-12-13.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef mycoin_Account_h
#define mycoin_Account_h
#include <time.h>
#include <string>

#define ACCOUNT_DEPOSIT ""
#define ACCOUNT_EXCHANGE ""
#define ACCOUNT_EXCHANGE ""
#define ACCOUNT_SUBSCRIPTION ""
#define ACCOUNT_BTC_EXCHANGE ""
#define ACCOUNT_BTC_FORSALE ""
#define ACCOUNT_BTC_DEPOSIT ""

#define ACCOUNT_LTC_EXCHANGE ""
#define ACCOUNT_LTC_DEPOSIT ""
#define ACCOUNT_LTC_FORSALE ""

#define ACCOUNT_FEE_TRANSACTION ""
#define ACCOUNT_CASH ""
#define ACCOUNT_INCOME_TRANSACTION ""
#define ACCOUNT_REFUND ""

typedef enum balance_type_t{REAL_TIME, WEEK, MONTH, YEAE} balance_type_t;
typedef int money_t;
using namespace std;
class Account{
protected:
    const string& code;
    const string& owner;
    time_t start_time;
    time_t end_time;
    money_t balance;
protected:
    virtual bool debit(time_t occurTime, money_t  money){return false;}
    virtual bool credit(time_t  occurTime, money_t  money){return false;}
    friend class AccountSuite;
public:
    money_t geBalance() { return balance;}
    Account(const string& owner, const string& code):code(code), owner(owner){}
};


//AccountSuite
//owner, create_time, description, start_time, end_time
class AccountSuite{
protected:
    const string& owner;
    time_t create_time;
    string description;
    time_t start_time;
    time_t end_time;
    
    AccountingVoucher& voucher;
    map<string, Account> accountMap;
    
public:
    AccountSuite(AccountingVoucher& voucher):voucher(voucher){};
    Account& getAccount(const string& code);
    AccountSuite(const string& name):owner(name){}
    
    bool account(const string& debitCode, const string& creditCode, money_t money){
        time_t now;
        time(&now);
        voucher.account( now, this, debitCode, creditCode, money);
    }
    bool account(Account& debitAccount, Account& creditAccount, money_t  money){
        return account( debitAccount.code, creditAccount.code, money);
    }
};

//记账凭证
class AccountingVoucher{
public:
    bool account(time_t now, AccountSuite& suit, const string& debitCode, const string& creditCode,  money_t  money);
    
};

#endif
<file_sep>//
//  IdentifyQuoteQueueTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__IdentifyQuoteQueueTest__
#define __mycoin__IdentifyQuoteQueueTestt__

#include "gtest/gtest.h"
#include "../IdentifyQuoteQueue.h"

#endif 
<file_sep>//
//  MessageConvertor.h
//  mycoin
//
//  Created by lx on 14-1-8.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef __mycoin__MessageConvertor__
#define __mycoin__MessageConvertor__
#include "message.h"

template <typename Message>
struct message_traits {
    typedef bool (* convert_func_type)(char *, Message &) ;
    typedef bool (* identify_func_type)(MessageHeader &) ;
};

template<typename message_type>
bool convertMessage( char *buf, size_t len, message_type & msg, typename message_traits<message_type>::identify_func_type identify_func, typename message_traits<message_type>::convert_func_type convert_func){
    unsigned long Message_get_delimited_size(void *_buffer, int offset);
    MessageHeader header;
    /*
     * Tests whether a message can be completely read from the given buffer at
     * the offset. The bytes [offset..offset+length-1] are interpreted.
     *,
     * Returns 1 (true) if buffer[offset..offset+length-1] contains a complete
     * message or 0 (false) otherwise.
     */
    do{
        if( Message_can_read_delimited_from(buf, 0, MAX_MessageHeader_SIZE) == 0)
            break;
        
        /*
         * Serialize a Person-message into the given buffer at offset and return
         * new offset for optional next message.
         */
        int MessageHeader_write_delimited_to(struct MessageHeader *_MessageHeader, void *_buffer, int offset);
        
        
        MessageHeader_read_delimited_from(buf, &header, 0);
        
        if(identify_func(header)){
            //以后将统一生成message，不再把message分散到各处
            return  convert_func(buf, msg);
        }
    }while (false);
    
    return false;
    
}




#endif /* defined(__mycoin__MessageConvertor__) */
<file_sep>//
//  QuoteMatchProcessorTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__QuoteMatchProcessorTest__
#define __mycoin__QuoteMatchProcessorTest__

#include "gtest/gtest.h"
#include "../QuoteMatchProcessor.h"

#endif /* defined(__mycoin__QuoteProcessorSetTest__) */
<file_sep>//
//  ContractNoteAccounter.cpp
//  mycoin
//
//  Created by lx on 14-1-9.
//  Copyright (c) 2014年 lx. All rights reserved.
//
#include "account_message.h"
#include <soci/soci.h>
#include "ContractNoteAccounter.h"
#include "Account.h"
#include "BizAccount.h"
#include "AccountSuiteFactory.h"

void ContractNoteProcessor::account(ContractNote &note){
    do{
        
        money_t money = note.price*note.quality;
        money_t fee = money* 5 /1000;

        const string & platform = "platform";
        ResiVoucher voucher (switcher);
        //买方借记资产，贷记资产往来
        if(voucher.account_multi(note.buyer, BizAccount::getDeposit(note.code), BizAccount::getExchange(note.code),note.quality))
            break;
        //买方借记资金往来，贷记押金
        if(voucher.account_multi(note.buyer, ACCOUNT_EXCHANGE, ACCOUNT_SUBSCRIPTION,money))
            break;
        //买方 借记手续费（成交价*数量*比例） 贷记 deposit，如果没钱了，那么借记手续费，贷记应付费用
        if(voucher.account_multi(note.buyer, ACCOUNT_FEE_TRANSACTION, /*deposit_balance >= money or payable*/ACCOUNT_DEPOSIT,  fee))
            break;
        
        //卖方 借记exchange，贷记forsale
        if(voucher.account_multi(note.seller, BizAccount::getExchange(note.code), BizAccount::getForsale(note.code),note.quality))
            break;
        //卖方成交后 借记deposit，贷记资金往来
        if(voucher.account_multi(note.seller, ACCOUNT_DEPOSIT, ACCOUNT_EXCHANGE,money))
            break;
        //卖方手续费 借记手续费（成交价*数量*比例） 贷记 deposit
        if(voucher.account_multi(note.seller, ACCOUNT_FEE_TRANSACTION, /*seller_deposit_balance >= money or payable*/ACCOUNT_DEPOSIT , fee))
            break;
        
        //平台 借计cash 贷记收入 描述　交易号
        if(voucher.account_multi(platform, ACCOUNT_CASH, ACCOUNT_INCOME_TRANSACTION, fee))
            break;
        
        //平台 买方收入　借计cash 贷记收入 描述　交易号
        if(voucher.account_multi(platform, ACCOUNT_CASH, ACCOUNT_INCOME_TRANSACTION, fee))
            break;
        
        //平台 返还卖方 借记退款 refund，贷记cash
        if(voucher.account_multi(platform, ACCOUNT_REFUND,ACCOUNT_CASH, fee))
            break;
        //卖方手续费 借记deposit，贷记退回费用或手续费
        if(voucher.account_multi(note.seller, ACCOUNT_DEPOSIT, ACCOUNT_FEE_TRANSACTION, fee))
            break;
        
        //平台 返还买方 借记退款 refund，贷记cash
        if(voucher.account_multi(platform, ACCOUNT_REFUND,ACCOUNT_CASH, fee))
            break;
        //买方 借记deposit，贷记退回费用或手续费
        if(voucher.account_multi(note.buyer, ACCOUNT_DEPOSIT, ACCOUNT_FEE_TRANSACTION, fee))
            break;
        voucher.submit();
      
    }while(false);
    
}

<file_sep>//
//  Account.cpp
//  mycoin
//
//  Created by lx on 13-12-28.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "Account.h"


    /*
     private:
     multimap<money_t, Account*> m_debitList, m_creditList;
     struct Compare
     {
     bool operator()(const Account& s1, const Account& s2) const
     {
     return strcmp(s1, s2) < 0;
     }
     };
     
     public :
     
     
     void debit(Account* debitAccount, money_t const & money){
     m_debitList.insert(pair<money, debitAccount>);
     }
     
     void credit(Account* creditAccount, money_t const & money){
     m_creditList.insert<money,creditAccount>;
     }
     
     bool account(){
     //校验两个列表金额时候相等
     //事务处理
     return true;
     }
     */
Account& AccountSuite::getAccount(const string& code){
    map<string, Account>::iterator iter = accountMap.find(code);
    if(iter == accountMap.end()){
        //  iter = accountMap.insert(pair<string, Account>(code, DatabaseAccount(owner,code, ses)));
    }
    return iter->second;
}

<file_sep>//
//  DatabaseAccount.h
//  mycoin
//
//  Created by lx on 13-12-15.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__DatabaseAccount__
#define __mycoin__DatabaseAccount__
#include <string>
#include <map>
#include <soci/soci.h>
#include "Account.h"

using namespace std;
using namespace soci;

class DatabaseVoucher :public AccountingVoucher{
public:
    bool account(time_t now, AccountSuite& suit, const string& debitCode, const string& creditCode,  money_t  money);
    
};


#endif /* defined(__mycoin__DatabaseAccount__) */
<file_sep>//
//  RedisAccount.h
//  mycoin
//
//  Created by lx on 14-1-11.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef __mycoin__RedisAccount__
#define __mycoin__RedisAccount__

//
//  DatabaseAccount.h
//  mycoin
//
//  Created by lx on 13-12-15.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__DatabaseAccount__
#define __mycoin__DatabaseAccount__
#include <string>
#include "Account.h"

using namespace std;
class RedisVoucher:public AccountVoucher{
private:
    EventSwitcher &switcher;
    map<string, Account> accountMap;
    
public:
    RedisVoucher(EventSwitcher &switcher):switcher(switcher){}
    Account& getAccount(const string& code);
    bool account( AccountSuite& suit, const string& debitCode, const string& creditCode,  money_t  money);
    bool account( AccountSuite& suit, const string& debitCode, const string& creditCode,  money_t  money);
    void submit();
};





#endif /* defined(__mycoin__RedisAccount__) */
<file_sep>//
//  QuoteProcessorSetTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__LimitPriceStrategyTest__
#define __mycoin__LimitPriceStrategyTest__

#include "gtest/gtest.h"
#include "../LimitPriceStrategy.h"

#endif 
<file_sep>//
//  Singleton.h
//  mycoin
//
//  Created by lx on 14-1-6.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef mycoin_Singleton_h
#define mycoin_Singleton_h

template<typename InnerSingleton, int sub=0 >
class Singleton{
private:
    static InnerSingleton *_instance;
    Singleton(){}
public:
    ~Singleton(){
        delete _instance;
        _instance = 0;
    }
    
    static InnerSingleton&  instance(){
        if(_instance == 0)
            _instance = new InnerSingleton();
        return *_instance;
    }
    
    static void  setInstance(InnerSingleton* single){
        if(single != NULL){
            if(_instance != NULL){
                delete _instance;
            }
            _instance = single;
        }
};

#endif
<file_sep>/******************************************************************* 
 * Header file generated by Protoc for Embedded C.                 *
 * Version 1.0M4 (2013-03-31)                                      *
 *                                                                 *
 * Copyright (c) 2009-2013                                         *
 * Technische Universitaet Muenchen                                *
 * http://www4.in.tum.de/                                          *
 *                                                                 *
 * Source : Message.proto
 *                                                                 *
 * Do not edit.                                                    *
 *******************************************************************/

#ifndef _Message_H
#define _Message_H

#ifdef __cplusplus
  extern "C" {
#endif

#define MAX_REPEATED_LENGTH 100
#define MAX_STRING_LENGTH 21

/*******************************************************************
 * General functions
 *******************************************************************/

/*
 * returns the size of a length delimited message which also 
 * contains the first bytes for the length encoding.
 */
unsigned long Message_get_delimited_size(void *_buffer, int offset);

/*
 * Tests whether a message can be completely read from the given buffer at
 * the offset. The bytes [offset..offset+length-1] are interpreted.
 *
 * Returns 1 (true) if buffer[offset..offset+length-1] contains a complete
 * message or 0 (false) otherwise.
 */
int Message_can_read_delimited_from(void *_buffer, int offset, unsigned int length);


/*******************************************************************
 * Enumeration: Message.proto, line 5
 *******************************************************************/
enum security_bill_t {
    BUY_IN_LIMIT_PRICE = 0,
    SELL_OUT_LIMIT_PRICE = 1,
    BUY_IN_MARKET_PRICE = 2,
    SELL_OUT_MARKET_PRICE = 3,
    BUY_WITHDRAW = 4,
    SELL_WITHDRAW = 5,
    ACCOUNT_CHARGE = 6,
    ACCOUNT_WITHDRAW = 7,
    CONTRACT_NOTE = 8
};


/*******************************************************************
 * Enumeration: Message.proto, line 17
 *******************************************************************/
enum bill_status_t {
    STATUS_NEW = 0,
    STATUS_PROCESSED = 1,
    STATUS_ACCEPTED = 2,
    STATUS_REJECTED = 3,
    STATUS_FINISHED = 4,
    STATUS_INVALID = 5
};


/*******************************************************************
 * Enumeration: Message.proto, line 26
 *******************************************************************/
enum message_type_t {
    UNKOWN_MESSAGE = 0,
    SECURITY_QUOTE = 1,
    WITHDRAW_QUOTE = 2,
    CONTRACT_NOTE = 3,
    ACCOUNT_EXCHANGE_NOTE = 4
};



/*******************************************************************
 * Message: Message.proto, line 35
 *******************************************************************/

/* Maximum size of a serialized SecurityQuote-message, useful for buffer allocation. */
#define MAX_SecurityQuote_SIZE 82

/* Structure that holds a deserialized SecurityQuote-message. */
struct SecurityQuote {
    enum message_type_t msg_type;
    enum security_bill_t billType;
    unsigned long billId;
    unsigned long occurTime;
    enum bill_status_t status;
    unsigned long long code;
    unsigned long price;
    unsigned long quality;
    unsigned long guaranty;
    int _client_len;
    char client[MAX_STRING_LENGTH];
};

/*
 * Serialize a Person-message into the given buffer at offset and return
 * new offset for optional next message.
 */
int SecurityQuote_write_delimited_to(struct SecurityQuote *_SecurityQuote, void *_buffer, int offset);

/*
 * Serialize a Person-message together with its tag into the given buffer 
 * at offset and return new offset for optional next message.
 * Is useful if a Person-message is embedded in another message.
 */
int SecurityQuote_write_with_tag(struct SecurityQuote *_SecurityQuote, void *_buffer, int offset, int tag);

/*
 * Deserialize a Person-message from the given buffer at offset and return
 * new offset for optional next message.
 *
 * Note: All fields in _Person will be reset to 0 before _buffer is interpreted.
 */
int SecurityQuote_read_delimited_from(void *_buffer, struct SecurityQuote *_SecurityQuote, int offset);


/*******************************************************************
 * Message: Message.proto, line 49
 *******************************************************************/

/* Maximum size of a serialized WithdrawQuote-message, useful for buffer allocation. */
#define MAX_WithdrawQuote_SIZE 68

/* Structure that holds a deserialized WithdrawQuote-message. */
struct WithdrawQuote {
    enum message_type_t msg_type;
    enum security_bill_t billType;
    unsigned long billId;
    unsigned long occurTime;
    enum bill_status_t status;
    unsigned long long code;
    unsigned long refBillId;
    int _client_len;
    char client[MAX_STRING_LENGTH];
};

/*
 * Serialize a Person-message into the given buffer at offset and return
 * new offset for optional next message.
 */
int WithdrawQuote_write_delimited_to(struct WithdrawQuote *_WithdrawQuote, void *_buffer, int offset);

/*
 * Serialize a Person-message together with its tag into the given buffer 
 * at offset and return new offset for optional next message.
 * Is useful if a Person-message is embedded in another message.
 */
int WithdrawQuote_write_with_tag(struct WithdrawQuote *_WithdrawQuote, void *_buffer, int offset, int tag);

/*
 * Deserialize a Person-message from the given buffer at offset and return
 * new offset for optional next message.
 *
 * Note: All fields in _Person will be reset to 0 before _buffer is interpreted.
 */
int WithdrawQuote_read_delimited_from(void *_buffer, struct WithdrawQuote *_WithdrawQuote, int offset);


/*******************************************************************
 * Message: Message.proto, line 61
 *******************************************************************/

/* Maximum size of a serialized ContractNote-message, useful for buffer allocation. */
#define MAX_ContractNote_SIZE 113

/* Structure that holds a deserialized ContractNote-message. */
struct ContractNote {
    enum message_type_t msg_type;
    enum security_bill_t billType;
    unsigned long billId;
    unsigned long occurTime;
    enum bill_status_t status;
    unsigned long long code;
    unsigned long price;
    unsigned long quality;
    unsigned long sourceBillId;
    unsigned long peerBillId;
    int _buyer_len;
    char buyer[MAX_STRING_LENGTH];
    int _seller_len;
    char seller[MAX_STRING_LENGTH];
};

/*
 * Serialize a Person-message into the given buffer at offset and return
 * new offset for optional next message.
 */
int ContractNote_write_delimited_to(struct ContractNote *_ContractNote, void *_buffer, int offset);

/*
 * Serialize a Person-message together with its tag into the given buffer 
 * at offset and return new offset for optional next message.
 * Is useful if a Person-message is embedded in another message.
 */
int ContractNote_write_with_tag(struct ContractNote *_ContractNote, void *_buffer, int offset, int tag);

/*
 * Deserialize a Person-message from the given buffer at offset and return
 * new offset for optional next message.
 *
 * Note: All fields in _Person will be reset to 0 before _buffer is interpreted.
 */
int ContractNote_read_delimited_from(void *_buffer, struct ContractNote *_ContractNote, int offset);


/*******************************************************************
 * Message: Message.proto, line 78
 *******************************************************************/

/* Maximum size of a serialized AccountExchangeNote-message, useful for buffer allocation. */
#define MAX_AccountExchangeNote_SIZE 68

/* Structure that holds a deserialized AccountExchangeNote-message. */
struct AccountExchangeNote {
    enum message_type_t msg_type;
    enum security_bill_t billType;
    unsigned long billId;
    unsigned long occurTime;
    enum bill_status_t status;
    unsigned long long code;
    unsigned long quality;
    int _client_len;
    char client[MAX_STRING_LENGTH];
};

/*
 * Serialize a Person-message into the given buffer at offset and return
 * new offset for optional next message.
 */
int AccountExchangeNote_write_delimited_to(struct AccountExchangeNote *_AccountExchangeNote, void *_buffer, int offset);

/*
 * Serialize a Person-message together with its tag into the given buffer 
 * at offset and return new offset for optional next message.
 * Is useful if a Person-message is embedded in another message.
 */
int AccountExchangeNote_write_with_tag(struct AccountExchangeNote *_AccountExchangeNote, void *_buffer, int offset, int tag);

/*
 * Deserialize a Person-message from the given buffer at offset and return
 * new offset for optional next message.
 *
 * Note: All fields in _Person will be reset to 0 before _buffer is interpreted.
 */
int AccountExchangeNote_read_delimited_from(void *_buffer, struct AccountExchangeNote *_AccountExchangeNote, int offset);



#ifdef __cplusplus
  }
#endif

#endif

<file_sep>//
//  RedisPublisher.cpp
//  mycoin
//
//  Created by lx on 13-12-31.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "RedisPublisher.h"

#include <string>
using namespace std;


void RedisPublisher::connect(const char *host, int port){
        
    context = redisAsyncConnect(host, port); //6379
    if (context->err) {
    }
        
}


void RedisPublisher::publish(const security_code_t code, security_price_t price, security_quality_t quality, security_price_t topBuyPrice[], security_quality_t topBuyQty[], int size1, security_price_t topSellPrice[], security_quality_t topSellQty[], int size2 ){
    if(context == NULL)
            return;
        /*
    std::streambuf json;
    json << "{price:" << price << ",quality:" << quality  << ",topbuys:[";
    for(int i=0; i< size1; i++){
        json<<  "{price:" << topBuyPrice[i] << ", quality:" << topBuyQty[i] << "},";
    }
    json << "], topsells:[";
    for(int i=0; i< size2; i++){
        json << "{price:" << topSellPrice[i] <<", quality:" << topSellQty[i] <<"},";
    }
    json << "]}";
    
    redisAsyncCommand(context, NULL, NULL, "publish /topic/stock/%b/routation %b"
                          ,code, strlen(code)
                          ,json, strlen(json));
     */
}

void RedisPublisher::publish(SecurityQuote &quote){
    if(context == NULL)
        return;
    /*
    std::streambuf json ;
    json << "{price:" << quote.price << ",quality:" << quote.quality
        << ",guanity:" << quote->guanity << ", status:" << quote.header.status +"}";

    redisAsyncCommand(context, NULL, NULL, "publish /topic/stock/queue/%b %b"
                      ,quote.header.billId, strlen(code)
                      ,json, strlen(json));
     */
}

int RedisPublisher::publish(ContractNote &note){
// 通知买了多少, 价格，数量都在变，原来的单到底是什么单，发布价格还是
    /*
     std::streambuf json ;
     json << "{price:" << quote.price << ",quality:" << quote.quality
     << ",guanity:" << quote->guanity << ", status:" << quote.header.status +"}";
     
     redisAsyncCommand(context, NULL, NULL, "publish /topic/stock/queue/%b %b"
     ,quote.header.billId, strlen(code)
     ,json, strlen(json));
     */
}
<file_sep>//
//  IdentifyQuoteQueye.h
//  mycoin
//
//  Created by lx on 13-12-23.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef mycoin_IdentifyQuoteQueue_h
#define mycoin_IdentifyQuoteQueue_h
#include "../quote.h"

typedef multimap<security_price_t, SecurityQuote> SellQuoteMultiMap;
typedef multimap<security_price_t, SecurityQuote,  greater<int>> BuyQuoteMultiMap;

template<typename SelfQuoteQueue, typename PeerQuoteQueue>
struct IdentifyQuoteQueue{
    
};

template<>
struct IdentifyQuoteQueue<BuyQuoteMultiMap,SellQuoteMultiMap>{
    BuyQuoteMultiMap &getSelfQueue(BuyQuoteMultiMap& buyQueue, SellQuoteMultiMap  &sellQueue){
        return buyQueue;
    }
    
    SellQuoteMultiMap &getPeerQueue(BuyQuoteMultiMap& buyQueue, SellQuoteMultiMap  &sellQueue){
        return sellQueue;
    }
};
template<>
struct IdentifyQuoteQueue<SellQuoteMultiMap,BuyQuoteMultiMap>{
    SellQuoteMultiMap &getSelfQueue(BuyQuoteMultiMap& buyQueue, SellQuoteMultiMap  &sellQueue){
        return sellQueue;
    }
    BuyQuoteMultiMap &getPeerQueue(BuyQuoteMultiMap& buyQueue, SellQuoteMultiMap& sellQueue){
        return buyQueue;
    }
};


#endif
<file_sep>#include <stdio.h>
#include <typeinfo>
#include <list>
template<typename t1,int param>
class TClass{
};


typedef TClass<int, 1> C1;
typedef TClass<int, 2> C2;

int main(){
   C1 c1;
   C2 c2;
   std::list<C1> clist;
   clist.push_back(c1);
   clist.push_back(c2);
/*
   if(typeid(C1) == typeid(C2)){
	printf("ok!");
   }else{
	printf("oh...");
  }
*/
}
<file_sep>//
//  LevelOfQuote.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__LevelOfQuote__
#define __mycoin__LevelOfQuote__
#include "../quote.h"
class LevelOfQuoteQueue{
private:
    int _level=0;
    security_billId_t _lastBillId = 0;
    security_price_t _lastPrice =0;
    
public:
    int level(security_billId_t billId, security_price_t peerPrice ){
        if(billId != _lastBillId){
            _level = 0;
            _lastPrice = 0;
            _lastBillId = billId;
        }
        if(peerPrice != _lastPrice){
            _lastPrice = peerPrice;
            ++_level;
        }
        return _level;
        
    }
};

#endif /* defined(__mycoin__LevelOfQuote__) */
<file_sep>//
//  AccountExchangeProcessor.h
//  mycoin
//
//  Created by lx on 13-12-27.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__AccountExchangeProcessor__
#define __mycoin__AccountExchangeProcessor__

#include "MessageProcessor.h"

class AccountExchangeProcessor:public MessageProcessor{
protected:
    typedef int (*)(AccountExchangeNote&) account_func_t;

    account_func_t account;
    
public:
    AccountExchangeProcessor(message_type msg_type, MessageProcessorMap* processorMap
                      , account_func_t account
                      )
        : MessageProcessor(msg_type,processorMap){
            this.account = account;
    }
    int execute(Event *msg, EventSwitcher& switcher){
        
    }
    int execute(AccountExchangeNote &quote, EventSwitcher& switcher){
        if(note.status != STATUS_NEW)
            return STATUS_REJECTED;
        switch(note.billType){
            case ACCOUNT_CHARGE:
                return charge(note,switcher);
            case ACCOUNT_WITHDRAW:
                return withdraw(note,switcher);
            default:
                return STATUS_REJECTED;
        }
    }

    int withdraw(AccountExchangeNote &note);
    int charge(AccountExchangeNote &note);
};


#endif
<file_sep>//
//  RoutineQuote.h
//  mycoin
//
//  Created by lx on 13-12-31.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__RoutineQuote__
#define __mycoin__RoutineQuote__
#include "quote.h"
#include "Publisher.h"
#include <hiredis/hiredis.h>
#include <hiredis/async.h>


class RedisPublisher:public Publisher{
private:
    redisAsyncContext *context =NULL;

public:
    void connect(const char *host, int port);
    redisAsyncContext * getContext(){
        return context;
    }
    
    void publish(SecurityQuote &quote);
    virtual void publish(const security_code_t code, security_price_t price, security_quality_t quality, security_price_t topBuyPrice[], security_quality_t topBuyQty[], int size1, security_price_t topSellPrice[], security_quality_t topSellQty[], int size2 );
    int publish (ContractNote &note);
};

#endif /* defined(__mycoin__RoutineQuote__) */
<file_sep>//
//  MessageProcessor.h
//  mycoin
//
//  Created by lx on 14-1-3.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef __mycoin__MessageProcessor__
#define __mycoin__MessageProcessor__
#include <map>
#include <list>
#include "message/message_extend.h"

using namespace std;
/*
  一致回调处理方式
 一致同步异步编程模型
 一致多线程，单线程模型
 
沙漠履带车安全不，不致陷落吧
 坦克太重，可以搞点耐热陶瓷，又轻
 */
typedef enum {
    ES_RUN_DEFAULT = 0,
    ES_RUN_ONCE,
    ES_RUN_NOWAIT
} es_run_mode;

template <int size>
class EventSwitcher{
protected:
    map<event_type, EventProcessor *> processorMap;
    typedef ReaderWriterQueue<Event> EventQueue; //vector<Event> EventQueue;
    typedef vector<EventQueue&> EventQueues;
    EventQueues queue(size);
public:
    void connect(EventProcessor);
    void push(Event &event, int rank);
    void now(Event &event);
    void run(es_run_mode run_mode); //once , process all until null, for ever
};

class EventProcessor{
public:
    event_type & const ev_type;
    
    EventProcessor(message_type& ev_type):ev_type(ev_type){

    }
    virtual int execute(Event &msg, EventSwitcher& switcher)=0;
};

class MessageProcessor;

typedef map<message_type, MessageProcessor*>  MessageProcessorMap;

class MessageProcessor{
public:
    message_type & msg_type;
    
    MessageProcessor(message_type& msg_type, MessageProcessorMap* processorMap):msg_type(msg_type){
        if(processorMap != NULL)
            processorMap->insert(msg_type, this);
    }
    virtual int execute(message_t *msg, list<message_t> &)=0;
};


#endif /* defined(__mycoin__Command__) */
<file_sep>//
//  thread_fn.h
//  mycoin
//
//  Created by lx on 14-1-9.
//  Copyright (c) 2014年 lx. All rights reserved.
//

#ifndef mycoin_thread_fn_h
#define mycoin_thread_fn_h
/*
#ifdef __cplusplus
extern "C"{
#endif
*/
struct thread_context_t{
    ReaderWriterQueue<message_t> * msgs;
    ReaderWriterQueue<message_t> * outs;
};

void match_fn(void *);

void io_fn(void *);

/*
#ifdef __cplusplus
}
#endif
*/

#endif
<file_sep>//
//  test.cpp
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "test.h"
#include "gtest/gtest.h"

int main(int argc, char **argv) {

    ::testing::AddGlobalTestEnvironment(new CoinExchangeTestEnvironment);
    ::testing::InitGoogleTest(&argc, argv);
    return RUN_ALL_TESTS();
}
<file_sep>//
//  QuoteQueue.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__QuoteQueue__
#define __mycoin__QuoteQueue__
#include <stdlib.h>
#include <algorithm>
#include <map>
#include <functional>
#include "../quote.h"


using namespace std;

typedef multimap<security_price_t, SecurityQuote> SellQuoteMultiMap;
typedef multimap<security_price_t, SecurityQuote,  greater<int>> BuyQuoteMultiMap;

//inline 应该允许调用方设定
class QuoteQueue{


    typedef map<security_code_t, SellQuoteMultiMap > SellQueueHash;
    typedef map<security_code_t, BuyQuoteMultiMap > BuyQueueHash;
    BuyQueueHash buyQueueHash;
    SellQueueHash sellQueueHash;
    
public:

    inline SellQuoteMultiMap* getSellQuoteQueue(security_code_t code){
        return innerQueue(sellQueueHash,code);
    }
    
    inline BuyQuoteMultiMap* getBuyQuoteQueue(security_code_t code){
        return innerQueue(buyQueueHash,code);
    }
    
    
    void clearQueue(){
        buyQueueHash.clear();
        sellQueueHash.clear();
    }
private:
    template<typename QueueHash>
    inline typename QueueHash::mapped_type * innerQueue(QueueHash& queueHash, security_code_t code){
        return &queueHash[code];

    }
};

#endif /* defined(__mycoin__QuoteQueue__) */
<file_sep>//
//  LevelOfQuoteTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "LevelOfQuoteTestQueue.h"


namespace {
    
    TEST(LevelOfQuoteQueueTest, matchQuoteSucceess) {
        LevelOfQuoteQueue levelQueue;
        
        security_billId_t billId = -1;
        security_price_t price = -1;
        ASSERT_EQ(0, levelQueue.level(billId, price));
        
        security_billId_t billId = -1;
        security_price_t price = -1;
        ASSERT_EQ(0,matchQuote(&quote, &notes));
        
        security_billId_t billId = -1;
        security_price_t price = 2;
        ASSERT_EQ(1,matchQuote(&quote, &notes));
        
        security_billId_t billId = -1;
        security_price_t price = 2;
        ASSERT_EQ(1,matchQuote(&quote, &notes));
        
        security_billId_t billId = -1;
        security_price_t price = -1;
        ASSERT_EQ(2,matchQuote(&quote, &notes));
        
        security_billId_t billId = 0;
        security_price_t price = -1;
        ASSERT_EQ(0,matchQuote(&quote, &notes));
    }
    
}  // namespace<file_sep>coinExchange
============

虚拟货币竞价交易平台
<file_sep>//
//  BizAccount.h
//  mycoin
//
//  Created by lx on 13-12-28.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__BizAccount__
#define __mycoin__BizAccount__
#include <string>
#include "Account.h"

using namespace std;
class BizAccount{
public:
    static const char* getDeposit(int code){
        switch (code) {
            case 0:
                return ACCOUNT_DEPOSIT;
                break;
            case 1:
                return ACCOUNT_BTC_DEPOSIT;
            case 2:
                return ACCOUNT_LTC_DEPOSIT;
            default:
                return "";
        }
    }
    
    static const char* getExchange(int code){
        switch (code) {
            case 00:
                return ACCOUNT_EXCHANGE;
                break;
            case 1:
                return ACCOUNT_BTC_EXCHANGE;
            case 2:
                return ACCOUNT_LTC_EXCHANGE;
            default:
                return "";
        }
    }
    
    static const char* getForsale(int code){
        switch (code) {
            case 0:
                return "";
                break;
            case 1:
                return ACCOUNT_BTC_FORSALE;
            case 2:
                return ACCOUNT_LTC_FORSALE;
            default:
                return "";
        }
    }
};

#endif /* defined(__mycoin__BizAccount__) */
<file_sep>/
//  CoinExchangeTestEnvironment.cpp
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "CoinExchangeTestEnvironment.h"

void CoinExchangeTestEnvironment::SetUp()
{
    srand((unsigned)time(0));
    std::cout << "CoinExchange Environment SetUP" << std::endl;
}

void CoinExchangeTestEnvironment::TearDown()
{
        std::cout << "CoinExchange Environment TearDown" << std::endl;
}<file_sep>//
//  match.c
//  mycoin
//
//  Created by lx on 13-12-27.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include <stdio.h>
#include <unistd.h>
#include <iostream>
#include <istream>
#include <ostream>
#include <string>

#include "match.h"
#include "message.h"

#include "Singleton.h"
#include "readerwriterqueue.h"
#include "WithdrawProcessor.h"
#include "QuoteProcessor.h"
#include "Singleton.h"
#include "match/match_quote.h"

using namespace std;
using namespace moodycamel;

template<> MessageProcessorMap * Singleton<MessageProcessorMap, 2>::_instance = NULL;
template<> MessageProcessorMap * Singleton<MessageProcessorMap, 3>::_instance = NULL;

void match_fn(void * arg){
    
    struct thread_context_t *context = (struct threadContext *)arg;
    ReaderWriterQueue<message_t> & msgs = *(context->msgs);
    ReaderWriterQueue<message_t> & outs = *(context->outs);
    
    MessageProcessorMap &processorMap = Singleton<MessageProcessorMap, 2>::instance();
    WithdrawProcessor withdrawer(WITHDRAW_QUOTE, &processorMap, NULL, matchWithdraw, NULL);
    QuoteProcessor quoteProcessor(SecurityQuote, &processorMap, NULL, matchQuote, NULL) ;

    
    message_t msg;
    list<message_t> out_msg_list;
    extern bool g_run;
    while(g_run){
        while(msgs.try_dequeue(msg)){
            MessageProcessorMap::iterator iter = processorMap.find(msg->quote.msg_type);
            if(iter != processorMap.end()){
                int status = iter->second->execute(msg, out_msg_list);
                if(status == STATUS_INVALID){
                    //outs.enqueue(*iter);
                }else{
                    for(list<message_t>::iterator iter = out_msg_list.begin(); iter!= out_msg_list.end(); iter++){
                        outs.enqueue(*iter);
                    }
                    out_msg_list.clear();
                    outs.enqueue(msg);
                }
            }
        }
    }
}

void io_fn(void *arg){
    
    struct thread_context_t *context = (struct threadContext *)arg;
    ReaderWriterQueue<message_t> & msgs = *(context->msgs);
    ReaderWriterQueue<message_t> & outs = *(context->outs);
    
    MessageProcessorMap &processorMap = Singleton<MessageProcessorMap, 3>::instance();
    
    QuoteProcessor(SECURITY_QUOTE, &processorMap
                   , prepareQuote, NULL, accoutQuote);
    WithdrawProcessor withdrawProcessor(WITHDRAW_QUOTE, &processorMap
                , prepareWithdraw, NULL, accoutWithdraw);
    ContractNoteProcessor noteProcessor(CONTRACT_NOTE, &processorMap
                        ,accountNote);
    AccountExchangeProcessor exchangeProcessor(ACCOUNT_EXCHANGE_NOTE, &processorMap
                        , accountExchange );
    
    message_t msg;
    list<message_t> out_msg_list;
    extern bool g_run;
    while(g_run){
        if(! msgs.try_dequeue(msg))
            continue;

        MessageProcessorMap::iterator iter = processorMap.find(msg->quote.msg_type);
        if(iter != processorMap.end()){
            int status = iter->second->execute(msg, out_msg_list);
            if(status == STATUS_INVALID){
               // outs.enqueue(*iter);
            }else{
                for(list<message_t>::iterator iter = out_msg_list.begin(); iter!= out_msg_list.end(); iter++){
                    outs.enqueue(*iter);
                }
                out_msg_list.clear();
                outs.enqueue(msg);
            }
        }
    }
}

<file_sep>//
//  match_quote.h
//  mycoin
//
//  Created by lx on 13-12-23.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__match_quote__
#define __mycoin__match_quote__

#include "../message.h"

int matchQuote(SecurityQuote &quote);
int matchWithdraw(WithdrawQuote &quote);

#endif 
<file_sep>//
//  QuoteWithdrawProcessorTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__QuoteWithdrawProcessorTest__
#define __mycoin__QuoteWithdrawProcessorTest__

#include "gtest/gtest.h"
#include "../QuoteWithDrawProcessor.h"

#endif
<file_sep>//
//  matchTest.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__matchTest__
#define __mycoin__matchTest__

#include "gtest/gtest.h"

#endif /* defined(__mycoin__matchTest__) */
<file_sep>//
//  QuoteProcessorSetTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "IdentifyQuoteQueueTest.h"
#include <typeinfo>

namespace {
    TEST(IdentifyQuoteQueue, SelfBuy) {
        BuyQuoteMultiMap buyQueue;
        SellQuoteMultiMap  sellQueue;
        
        IdentifyQuoteQueue<BuyQuoteMultiMap,SellQuoteMultiMap> identify1;
        ASSERT_EQ(&buyQueue, identify1.getSelfQueue(&buyQueue, &sellQueue));
        ASSERT_EQ(&sellQueue, identify1.getPeerQueue(&buyQueue, &sellQueue));
        
    }
    
    TEST(IdentifyQuoteQueue, SelfSell) {
        BuyQuoteMultiMap buyQueue;
        SellQuoteMultiMap  sellQueue;
        
        
        IdentifyQuoteQueue<SellQuoteMultiMap,BuyQuoteMultiMap> identify2;
        ASSERT_EQ(&sellQueue, identify2.getSelfQueue(&buyQueue, &sellQueue));
        ASSERT_EQ(&buyQueue, identify2.getPeerQueue(&buyQueue, &sellQueue));
        
    }
    
}  // namespace<file_sep>//
//  QuoteMatchProcessor.cpp
//  mycoin
//
//  Created by lx on 14-1-6.
//  Copyright (c) 2014年 lx. All rights reserved.
//
#include "match_quote.h"
#include <algorithm>
#include <vector>
#include <map>
#include <functional>

#include "../quote.h"
#include "MatchStrategy.h"
#include "lost.h"

#include "QuoteQueue.h"

using namespace std;


int matchQuote(SecurityQuote &quote){
    do{
        if(quote.status != STATUS_INQUEUE)
            break;
        QuoteQueue& quoteQueue = Singleton<QuoteQueue>::instance();
        SellQuoteMultiMap * sellQueue = quoteQueue.getSellQuoteQueue(quote->code);
        BuyQuoteMultiMap * buyQueue = quoteQueue.getBuyQuoteQueue(quote->code);
        if(sellQueue == NULL || buyQueue == NULL)
            return break;
        
        security_price_t price = 0;
        switch (quote.billType) {
            case BUY_IN_LIMIT_PRICE:
                price = matchQueue(quote,*buyQueue, *sellQueue, matchTopDown);
            case BUY_IN_MARKET_PRICE:
                price = matchQueue(quote,*buyQueue, *sellQueue, matchBottomUp);
            case SELL_OUT_LIMIT_PRICE:
                price = matchQueue(quote,*buyQueue, *sellQueue, marketPriceBuyIn );
            case SELL_OUT_MARKET_PRICE:
                price = matchQueue(quote,*buyQueue, *sellQueue, marketPriceSellOut);
            default:
                return STATUS_REJECTED;
        }
        //结束后如果要把quote转为限价订单
        //guanrity　数量得从订单和那个来保证了
        /* 转topone
         BuyQuoteMultiMap* buyQueue, SellQuoteMultiMap *sellQueue){
         SelfQuoteQueue *selfQueue = IdentifyQuoteQueue<SelfQuoteQueue, PeerQuoteQueue>::getSelfQueue(buyQueue, sellQueue);
         quote->price = selfQueue->begin()->price ;
         return quote;
         还得通知客户端才好
         
         */
        //这里只是撤销
        

        if(quote.quality > 0){
            SecurityQuote * quoteReserved = postmatch(&quote, buyQueue, sellQueue);
            if(quoteReserved != NULL){
                SelfQuoteQueue &selfQueue = identify.getSelfQueue(buyQueue, sellQueue);
                selfQueue.insert(make_pair(quote.price,quote));
                quote.status = STATUS_PROCESSING;
            }
        }
        quote.status = STATUS_PROCESSED;
        return quote.status;
    }while(false);
    
    return STATUS_REJECTED;
}

struct isQuoteFinished : public std::unary_function<SecurityQuote, bool> {
    bool operator()(const SecurityQuote & x) const {
        return x.quality <= 0;
    }
};


template<typename SelfQuoteQueue, typename PeerQuoteQueue, typename MatchStrategy>
security_price_t QuoteMatchProcessor::matchQueue(SecurityQuote &quote, SelfQuoteQueue& selfQueue, PeerQuoteQueue  &peerQueue, MatchStrategy &matchStrategy){

    security_price_t lastPrice =0;
    typename PeerQuoteQueue::iterator iter;
    for(iter = peerQueue.begin(); iter != peerQueue.end(); iter++){
        security_quality_t quality = matchStrategy(quote, iter->second);
        if(quality >0 ){
            ContractNote note;
            note.code = quote.code;
            note.sourceBillId = quote.header.billId;
            note.peerBillId = iter->second.header.billId;
            memcpy(&note.buyer, quote.client , sizeof(quote.client));
            memcpy(&note.seller, iter->second.client , sizeof(iter->second.client));
            
            note.quality = quality;
            note.price = iter->second.price;
            
            notes_push_back(note);
            
            lastPrice = note.price;
            
            //对方数量＝＝０时，生成quote完成单
            if(iter->second.quality == 0){
                finishQuote(&iter->second);
            }
        }else{
            break;
        }
    }
    
    map_erase_if(peerQueue,
                 compose1(isQuoteFinished(),select2nd<map<security_price_t, SecurityQuote>::value_type>()));
    return lastPrice;
}

template<typename SelfQuoteQueue, typename PeerQuoteQueue>
static int withdraw(WithdrawQuote &quote, SelfQuoteQueue &selfQueue,  PeerQuoteQueue & peerQueue){
    
    for(typename SelfQuoteQueue::iterator iter = selfQueue.begin(); iter!=selfQueue.end(); iter++){
        if(quote.refBillId == iter->second.header.billId){
            finishQuote(&iter->second); //原单完成
            selfQueue.erase(iter);
            break;
        }
    }
    quote.status = STATUS_PROCESSED;
    return quote.status;
}


int matchWithdraw(WithdrawQuote &quote){
    do{
        QuoteQueue& quoteQueue = Singleton<QuoteQueue>::instance();
        SellQuoteMultiMap * sellQueue = quoteQueue.getSellQuoteQueue(quote->code);
        BuyQuoteMultiMap * buyQueue = quoteQueue.getBuyQuoteQueue(quote->code);
        if(sellQueue == NULL || buyQueue == NULL)
            return break;
        
        switch (quote.billType) {
            case BUY_WITHDRAW:
                return withdraw(quote, *buyQueue, *sellQueue);
            case SELL_WITHDRAW:
                return withdraw(quote, *sellQueue, *buyQueue);
            default:
                break;
        }
    }while(false);
    
    return STATUS_REJECTED;
    
}
<file_sep>//
//  QuoteMatchProcessorTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "QuoteMatchProcessorTest.h"
#include <typeinfo>

namespace {
   

    
}  // namespace<file_sep>struct s1{
 int a;
};

struct s2{
 int b;
};
union message{
    struct {
	int a;
    };
    struct {
	int a;
	int b;
   };
};

int main(){
  union message msg;
  msg.b =20;
}
<file_sep>//
//  QuoteQueueTest.h
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__QuoteQueueTest__
#define __mycoin__QuoteQueueTest__

#include "gtest/gtest.h"
#include "../QuoteQueue.h"

#endif /* defined(__mycoin__QuoteProcessorSetTest__) */
<file_sep>//
//  test.cpp
//  mycoin
//
//  Created by lx on 13-12-17.
//  Copyright (c) 2013年 lx. All rights reserved.
//
#include <stdio.h>
#include <stdlib.h>
#include <uv.h>
#include <time.h>
#include "demo.h"
#include "quote.h"

static uv_shutdown_t shutdown_req;
static uv_write_t write_req;
struct sockaddr_in dest;
static uv_loop_t *loop;

static void write_cb(uv_write_t* req, int status) {
    

}

static void close_cb(uv_handle_t* handle) {
    uv_tcp_t socket;
    uv_tcp_init(loop, &socket);
    uv_connect_t connect;
    
    uv_tcp_connect(&connect, &socket, dest, on_connect);
}

static void shutdown_cb(uv_shutdown_t* req, int status) {
    
    uv_close((uv_handle_t*)req->handle, close_cb);
}

void on_connect(uv_connect_t* req, int status){
    
    SecurityQuote quote;
    time(&quote.occurTime);
    //撤销单
    //撤销买单，撤销卖单-简单，空单时
    //　有单时
    //　单已全部成交
    //　单成交部分
    //　单完全没成交
    //限价单
    //市价单
    quote.code = 1;//2
    quote.billId = (long)random();//hash
    quote.billType =  (security_bill_t)random()%4; // BUY_IN_LIMIT_PRICE, SELL_OUT_LIMIT_PRICE,
    
    quote.quality = random() %10;
    if(quote.billType == BUY_IN_LIMIT_PRICE || quote.billType == SELL_OUT_LIMIT_PRICE ){
        quote.price = 5000 + random()% 2000;
    }else{
        quote.guaranty = quote.quality * 6000; //BUY_IN_MARKET_PRICE,SELL_OUT_MARKET_PRICE,
    }
    
    uv_write(&write_req, req->handle, (char *)&quote, 1, write_cb);
    
    uv_shutdown(&shutdown_req, req->handle, shutdown_cb);
 
}


void thread_fn(void * arg){
    srand((unsigned)time(0));
    dest = uv_ip4_addr("127.0.0.1", 7000);
    
    loop = uv_loop_new();
    uv_tcp_t socket;
    uv_tcp_init(loop, &socket);
    uv_connect_t connect;
    
    uv_tcp_connect(&connect, &socket, dest, on_connect);
    uv_run(loop, UV_RUN_DEFAULT);
}

int main() {
    
    int tracklen = 10;
    for(int i=0; i< 2; i++){
        uv_thread_t tortoise_id;
        uv_thread_create(&tortoise_id, thread_fn, &tracklen);
        uv_thread_join(&tortoise_id);
    }
    
    return 0;
}<file_sep>//
//  lost.h
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef mycoin_lost_h
#define mycoin_lost_h
#define _LIBCPP_HAS_NO_RVALUE_REFERENCES
#include <stdlib.h>
using namespace std;

template <typename Map, typename F>
void map_erase_if(Map& m, F pred)
{
    for (typename Map::iterator i = m.begin();
         (i = find_if(i, m.end(), pred)) != m.end();
         m.erase(i++));
}

template <typename F,typename G>
class Compose_F_Gx : public std::unary_function<typename G::argument_type,typename F::result_type>
{
public:
    Compose_F_Gx(const F& _f,const G& _g):f(_f),g(_g)
    {
    }
    typename F::result_type
    operator()(const typename G::argument_type& x) const
    {
        return f(g(x));
    }
private:
    F f;
    G g;
};

template <typename F,typename G>
inline Compose_F_Gx<F,G> compose1(const F& f,const G& g)
{
    return Compose_F_Gx<F,G>(f,g);
}
 

template< typename Pair >
struct select1st:public unary_function<Pair, typename Pair::second_type>
 {
 
 const typename Pair::first_type & operator()(const Pair & p ) const
 {
 return p.first;
 }
 };

template< typename Pair >
 struct select2nd:public unary_function<Pair,typename Pair::second_type>
 {
 
 const typename Pair::second_type & operator()(const Pair & p) const
 {
 return p.second;
 }
 };



#endif
<file_sep>//
//  QuoteProcessorSetTest.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "LimitPriceStrategyTest.h"
#include <typeinfo>

namespace {

    
    TEST(TopLimitPriceStrategy, match) {

        TopLimitPriceStrategy strategy;
        SecurityQuote quote,cpmQuote;
        SecurityQuote peer,cpmPeer;
        security_quality_t qty;
        
        security_code_t code = random();
        quote.code = code;
        peer.code = code;
        
        quote.quality = random();
        peer.quality = random();
        
        quote.price = random();
        peer.price = random();
        memcpy(&cpmQuote, &quote);
        memcpy(&cpmpeer, &peer);
        
        qty = strategy.match(quote, peer);
        
        ASSERT_EQ(qty, cmpQuote.quality - quote.quality);
        ASSERT_EQ(qty, peer.quality - cmpPeer.quality);
        quote.quality -= qty;
        ASSERT_EQ(0, memcpm(&cmpQuote,&quote));
        peer.quality += qty;
        ASSERT_EQ(0, memcpm(&cmpPeer,&peer));
        
        if(quote.price >= peer.price){
            ASSERT_GT(qty,0);
            quote.price = peer.price -1;
            ASSERT_EQ(strategy.match(quote, peer),0);
        }else{
            ASSERT_EQ(qty,0);
            quote.price = peer.price +1;
            ASSERT_GT(strategy.match(quote, peer),0);
        }
        
        quote.quality = - random();
        qty = strategy.match(quote, peer);
        ASSERT_EQ(0, qty);
    }
    
    TEST(BottomLimitPriceStrategy, match) {
        
        BottomLimitPriceStrategy strategy;
        
        SecurityQuote quote,cpmQuote;
        SecurityQuote peer,cpmPeer;
        security_quality_t qty;
        
        security_code_t code = random();
        quote.code = code;
        peer.code = code;

        
        quote.quality = random();
        peer.quality = random();
        
        quote.price = random();
        peer.price = random();
        memcpy(&cpmQuote, &quote);
        memcpy(&cpmpeer, &peer);
        
        qty = strategy.match(quote, peer);
        
        ASSERT_EQ(qty, cmpQuote.quality - quote.quality);
        ASSERT_EQ(qty, peer.quality - cmpPeer.quality);
        quote.quality -= qty;
        ASSERT_EQ(0, memcpm(&cmpQuote,&quote));
        peer.quality += qty;
        ASSERT_EQ(0, memcpm(&cmpPeer,&peer));
        
        if(quote.price <= peer.price){
            ASSERT_GT(qty,0);
            quote.price = peer.price + 1;
            ASSERT_EQ(strategy.match(quote, peer),0);
        }else{
            ASSERT_EQ(qty,0);
            quote.price = peer.price - 1;
            ASSERT_GT(strategy.match(quote, peer),0);
        }
        
        quote.quality = - random();
        qty = strategy.match(quote, peer);
        ASSERT_EQ(0, qty);
        
    }
    
}  // namespace<file_sep>//
//  RoutineQuotation.cpp
//  mycoin
//
//  Created by lx on 13-12-24.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "RoutineQuotation.h"
#include "../Singleton.h"

template<> RoutineQuotation *Singleton<RoutineQuotation>::_instance = 0;

int RoutineQuotation::update(ContractNote &note){
    innerMap[note.code].sum += note.price * note.qty;
    innerMap[note.code].qty += note.qty;
    
    updateTopQuote(innerMap[code].topBuys,  note.price, -note.qty);
    updateTopQuote(innerMap[code].topSells,  price, -note.qty);

}

int RoutineQuotation::update(SecurityQuote &quote){
    switch(quote.billType){
        case BUY_IN_LIMIT_PRICE:
        case BUY_IN_MARKET_PRICE:
            updateTopQuote(innerMap[code].topBuys,  price, qty);
            break;
        case SELL_OUT_LIMIT_PRICE:
        case SELL_OUT_MARKET_PRICE:
            updateTopQuote(innerMap[code].topSells,  price, qty);
            break;
        default:
            break;
    }
}


void RoutineQuotation::publish(Publisher &publisher){

    for (InnerRoutineMap::iterator iter=innerMap.begin(); iter!=innerMap.end(); iter++) {
        
        int i = 0;
        security_price_t topBuyPrice[MAX_ROUTINE_LEVEL], topSellPrice[MAX_ROUTINE_LEVEL];
        security_quality_t topBuyQty[MAX_ROUTINE_LEVEL], topSellQty[MAX_ROUTINE_LEVEL];
        SellQuoteRoutine &topSells = iter->second.topSells;
        BuyQuoteRoutine &topBuys = iter->second.topBuys;
        for (SellQuoteRoutine::iterator iter2= topSells.begin(); iter2!=topSells.end() && i < MAX_ROUTINE_LEVEL ; iter2 ++ ) {
            topSellQty[i] = iter2->second;
            topSellPrice[i] = iter2->first;
            i++;
        }
        
        int j =0;
        for (BuyQuoteRoutine::iterator iter2= topBuys.begin(); iter2!=topBuys.end() && j < MAX_ROUTINE_LEVEL ; iter2 ++ ) {
            topBuyQty[j] = iter2->second;
            topBuyPrice[j] = iter2->first;
            j++;
        }
        
        publisher.publish( iter->first, iter->second.qty >0? iter->second.sum/iter->second.qty :0, iter->second.qty, topBuyPrice, topBuyQty, j, topSellPrice, topSellQty, j);
    }
    
    reset();
}
<file_sep>//
//  RedisAccount.cpp
//  mycoin
//
//  Created by lx on 14-1-11.
//  Copyright (c) 2014年 lx. All rights reserved.
//
/*
 使用nosql，在灾难恢复方面及其难处理。数据不一致，看起来可行的办法还是在源头保存事件，进行事件重演
 */
#include "RedisVoucher.h"
typdef struct account_context{
    EventSwitcher *switcher;
    Event event;
}account_context_t;

static void account_start(redisAsyncContext *c, void *r, void *privdata){
    account_context_t context = (account_context_t *) privdata;
    redisReply *reply = r;
    if (reply == NULL) {
        context->event.status = STATUS_ERROR;
    }else{
        switch(reply->type){
            case REDIS_REPLY_STRING:
                break;
            case REDIS_REPLY_ARRAY:
                for (j = 0; j < reply->elements; j++) {
                    printf("%u) %s\n", j, reply->element[j]->str);
                }
                break;
            case REDIS_REPLY_INTEGER:
                break;
            case REDIS_REPLY_NIL:
                break;
            case REDIS_REPLY_STATUS:
                break;
            case REDIS_REPLY_ERROR:
                break;
        }
        event.status = STATUS_ACCOUNTED;
    }
    typedef struct redisReply {
        int type; /* REDIS_REPLY_* */
        long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
        int len; /* Length of string */
        char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
        size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
        struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
    } redisReply;
    context->switcher->push(event);
}

static void account_cb(redisAsyncContext *c, void *r, void *privdata){
    account_context_t context = (account_context_t *) privdata;
    redisReply *reply = r;
    if (reply == NULL) {
        context->event.status = STATUS_ERROR;
    }else{
        switch(reply->type){
            case REDIS_REPLY_STRING:
                break;
            case REDIS_REPLY_ARRAY:
                for (j = 0; j < reply->elements; j++) {
                    printf("%u) %s\n", j, reply->element[j]->str);
                }
                break;
            case REDIS_REPLY_INTEGER:
                break;
            case REDIS_REPLY_NIL:
                break;
            case REDIS_REPLY_STATUS:
                break;
            case REDIS_REPLY_ERROR:
                break;
        }
        event.status = STATUS_ACCOUNTED;
    }
    typedef struct redisReply {
        int type; /* REDIS_REPLY_* */
        long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
        int len; /* Length of string */
        char *str; /* Used for both REDIS_REPLY_ERROR and REDIS_REPLY_STRING */
        size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
        struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
    } redisReply;
    context->switcher->push(event);
}

bool RedisVoucher::account(const string& suit, const string& debitCode, const string& creditCode,  money_t  money){
    
    const string key = suite +
    redisAsyncCommand(context, NULL, NULL, "MULTI");
    redisAsyncCommand(context, NULL, NULL, "WATCH %b");

    //debit
    redisAsyncCommand(context, account_start, NULL, "HMSET %b debit %b"
                      ,json, strlen(json),debitCode, strlen(debitCode));
    /*
    
    sql << "insert into " <<  detail_table << "(occur_time, debit, credit, owner) values( ?, ?, 0,?)", use(occurTime), use(money), use(owner);
    
    //balance_type 　时间
    sql << "update "  << table << " set occur_time=:occur_time, balance =banalce + " <<money << " where balance_type=" << 0 <<" and owner=:owner ", use(occurTime, "occur_time"),  use(owner, "owner");
    
    //credit
    sql << "insert into " <<  detail_table << "(occur_time, debit, credit, owner) values( ?, 0, ?,?)", use(occurTime),  use(money),use(owner);
    //balance_type 　时间
    sql << "update "  << table << " set occur_time=:occur_time, balance =banalce - " <<money << " where balance_type=" <<0 <<" and owner=:owner ", use(occurTime, "occur_time"),  use(owner, "owner");
    */
    redisAsyncCommand(context, NULL, NULL, "EXEC");
    return true;
    
}



<file_sep>//
//  quote.h
//  mycoin
//
//  Created by lx on 13-12-9.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef mycoin_quote_h
#define mycoin_quote_h

#include <time.h>
#include "message.h"

#ifdef __cplusplus
extern "C"{
#endif


typedef unsigned long long security_code_t;
typedef unsigned int security_price_t;
typedef unsigned int security_quality_t;
typedef unsigned int security_billId_t;

    
#ifdef __cplusplus
}
#endif



//交割单
/* java
class DeliveryOrder{
    int billId;
    int sourceBillId;
    time_t occrTime;
    class Item{
        int price;
        int quliaty;
        time_t occrTime;
    }
    public getItem();
};
 */
#endif
<file_sep>//
//  BizAccount.cpp
//  mycoin
//
//  Created by lx on 13-12-28.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "BizAccount.h"
<file_sep>//
//  MatchStrategy.cpp
//  mycoin
//
//  Created by lx on 13-12-21.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin__TopLimitPriceStrategy__
#define __mycoin__TopLimitPriceStrategy__
#include "../quote.h"
#include "MatchStrategy.h"

security_quality_t matchTopDown(SecurityQuote &quote, SecurityQuote & peer){
        
    if(quote.quality <=0 || quote.price < peer.price)
        return 0;
        
    security_quality_t qty = std::min(quote.quality,  peer.quality);
    quote.quality -= qty;
    peer.quality -= qty;
    return qty;
}



//sell out
security_quality_t matchBottomUp(SecurityQuote &quote, SecurityQuote & peer){
        
    if(quote.quality <=0 || quote.price > peer.price)
            return 0;
        
    security_quality_t qty = std::min(quote.quality,  peer.quality);
    quote.quality -= qty;
    peer.quality -= qty;
    return qty;
        
}
    

#define MAX_LEVEL 5;

static LevelOfQuoteQueue levelQueue;

security_quality_t marketPriceBuyIn(SecurityQuote &quote, SecurityQuote & peer){
    if(quote.quality > 0 || MAX_LEVEL > levelQueue.level(quote.billId, peer.price) ){
            
            //结束后要把quote转为限价订单
            //guanrity 转为price，是否要生成新的quote，在postMatch中处理
            security_quality_t qty = min(quote.quality,  peer.quality);
            if(quote.guaranty < peer.price * qty){
                qty = quote.guaranty / peer.price;
            }
            
            quote.guaranty -= peer.price * qty;
            quote.quality -= qty;
            peer.quality -= qty;
            return qty;
        }else{
            return 0;
        }
    }
    

security_quality_t marketPriceSellOut(SecurityQuote &quote, SecurityQuote & peer){
    if(quote.quality > 0 || maxLevel > levelQueue.level(quote.billId, peer.price) ){
        //市价卖出
        security_quality_t qty = std::min(quote.quality,  peer.quality);
        quote.quality -= qty;
        peer.quality -= qty;
        return qty;
    }else
        return 0;
}


#endif
<file_sep>//
//  QuoteQueue.cpp
//  mycoin
//
//  Created by lx on 13-12-22.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#include "QuoteQueue.h"
#include "../Singleton.h"

template<> QuoteQueue* Singleton<QuoteQueue>::_instance = NULL;<file_sep>//
//  MycoinApplication.h
//  mycoin-account
//
//  Created by lx on 13-12-25.
//  Copyright (c) 2013年 lx. All rights reserved.
//

#ifndef __mycoin_account__MycoinApplication__
#define __mycoin_account__MycoinApplication__
#include <Poco/Util/ServerApplication.h>

using namespace Poco;
using namespace Poco::Util;
using namespace std;
class MycoinApplication:public ServerApplication{
public:
    int main( const std::vector < std::string > & args);
protected:
    void handleOption(const std::string& name, const std::string& value){}
    
};

#endif /* defined(__mycoin_account__MycoinApplication__) */
