Arrx.c

[大目次 | 目次 | 関数 | マクロ]

大目次

目次

関数一覧

マクロ一覧


   1|/****************************************************************
   2|*  1. <<< 固定要素数配列 (ArrX) >>> 
   3|*・ArrX は任意の型の配列を統一的に用いるようにします。
   4|*・要素数を配列と別の変数にしないので、配列自体を1つの識別子だけで
   5|*  参照することができます。
   6|*    char  arr[50];  ...  char*  pArr;
   7|*    int   arr_n;         int*   pArr_n;
   8|*    ArrX  arr;      ...  ArrX*  pArr;
   9|*
  10|*  2. <<< 配列内の全要素を走査する >>>
  11|*・配列内の全要素を走査するには、次のようにします。
  12|*    ArrX*  arr;        // 配列
  13|*    type*  pElem;      // 要素へのポインタ
  14|*    type*  pElem_last;  // 最終要素の次のアドレス
  15|*
  16|*    pElem_last = arr->last;
  17|*    for ( pElem = arr->first; pElem < pElem_last; pElem++ ) {
  18|*      *pElem;   // 要素へのアクセス、ポインタ参照 '*' に注意
  19|*      pElem->member;
  20|*    }
  21|*****************************************************************/
  22|#include "mixer_precomp.h"  /* Auto precompiled header, Look at mixer-... folder */
  23|// #pragma hdrstop ("mixer_precomp")
  24|
  25|#define   STDLIBS_INCLUDE_STDIO_H
  26|#define   STDLIBS_INCLUDE_STRING_H
  27|#define   STDLIBS_INCLUDE_STDARG_H
  28|
  29|#if defined(USES_MXP_AUTOINC)
  30| #include "arrx.ah"  /* Auto include header, Look at mixer-... folder */
  31|#endif
  32|
  33|#include  <stdlib.h>
  34|
  35|#if defined(FOR_GHS) || defined(FOR_CA) || defined(FOR_WINCE)
  36|  #define  ARRX_NO_STRICMP
  37|#endif
  38| 
  39|/*-------------------------------------------------------------------------*/
  40|/* ◆3. <<<< (ArrX_C) C言語配列 >>>> */ 
  41|/*-------------------------------------------------------------------------*/
  42|
  43|
  44| 
  45|/***********************************************************************
  46|  3-1. <<< [ArrX_C_shaffle] 配列の内容をランダムにシャッフルする >>> 
  47|【引数】
  48|  ・void*  arr_adr;  配列の先頭アドレス
  49|  ・int  elem_size;  配列の要素のサイズ(バイト)
  50|  ・int  nElem;      配列の要素数
  51|  ・int  seed;       乱数の種(時刻など, -1= seed を使わない, 1=再初期化)
  52|************************************************************************/
  53|void  ArrX_C_shaffle( void* arr_adr, int elem_size, int nElem, int seed )
  54|{
  55|  int  i, j, x;
  56|  char  elem;
  57|  char*  p1;
  58|  char*  p2;
  59|
  60|  if ( seed != -1 )  srand( seed );
  61|
  62|  for ( i = 0; i < nElem; i++ ) {
  63|    j = nElem * rand() / (RAND_MAX+1);
  64|
  65|    p1 = (char*)arr_adr + elem_size * i;
  66|    p2 = (char*)arr_adr + elem_size * j;
  67|    for ( x = 0; x < elem_size; x++ ) {
  68|      elem = p1[x];  p1[x] = p2[x];  p2[x] = elem;
  69|    }
  70|  }
  71|}
  72|
  73| 
  74|/*-------------------------------------------------------------------------*/
  75|/* ◆4. <<<< 最小固定要素配列 (ArrX) >>>> */ 
  76|/*-------------------------------------------------------------------------*/
  77|
  78|#ifdef  USES_SYM
  79|SYM_STRUCT_START( ArrX )
  80|SYM_STRUCT_LOOP_FUNC( ArrX, ArrX_doLoopFunc )
  81|SYM_STRUCT_MEMB( ArrX, void*, first )
  82|SYM_STRUCT_MEMB( ArrX, void*, last )
  83|SYM_STRUCT_END( ArrX )
  84|#endif
  85|
  86| 
  87|/****************************************************************
  88|  4-1. <<< [ArrX_init] 初期化する(type1) >>> 
  89|【引数】
  90|  ・int  arr_sizeof;  全要素のデータのサイズ (byte)
  91|【補足】
  92|・次のように指定することで、確保したメモリ領域 arr のサイズに
  93|  関わらず、任意の要素数 n の type 型配列とすることができます。
  94|    ArrX_init( &arrx, arr, sizeof(type)* n );
  95|*****************************************************************/
  96|void  ArrX_init( ArrX* m, void* first, int arr_sizeof )
  97|{
  98|  ERRORS_INITCHK( m, 0 );
  99|
 100|  m->first = first;
 101|  m->last = (char*)first + arr_sizeof;
 102|
 103|  ASSERT( ArrX_chk( m ) );
 104|}
 105|
 106|
 107| 
 108|/****************************************************************
 109|  4-2. <<< [ArrX_init2] 初期化する(type2) >>> 
 110|【引数】
 111|  ・void* first;  配列の先頭アドレス
 112|  ・void* over;   配列の末尾の次の要素のアドレス
 113|【補足】
 114|・over には、たとえば、struct* p; に配列の末尾の要素のアドレスが
 115|  格納されている場合、p+1( (char*)p + sizeof(struct))を指定します。
 116|*****************************************************************/
 117|void  ArrX_init2( ArrX* m, void* first, void* over )
 118|{
 119|  ERRORS_INITCHK( m, 0 );
 120|
 121|  m->first = first;
 122|  m->last = over;
 123|
 124|  ASSERT( ArrX_chk( m ) );
 125|}
 126|
 127| 
 128|/****************************************************************
 129|  4-3. <<< [ArrX_initByStr] 文字列を ArrX 型にする >>> 
 130|*****************************************************************/
 131|void  ArrX_initByStr( ArrX* m, char* str )
 132|{
 133|  ERRORS_INITCHK( m, 0 );
 134|
 135|  m->first = str;
 136|  m->last = str + strlen( str );
 137|
 138|  ASSERT( ArrX_chk( m ) );
 139|}
 140|
 141|
 142| 
 143|/***********************************************************************
 144|  4-4. <<< [ArrX_initPtrArr_imp] ポインタ配列を作る >>> 
 145|【補足】
 146|・ArrX_initPtrArr の実装部です。
 147|************************************************************************/
 148|void  ArrX_initPtrArr_imp( ArrX* m, ArrX_Buf* buf, ArrX* arr,
 149|  int elem_size )
 150|{
 151|  char*  pElem;    /* arr の要素 */
 152|  char*  pElem_over;
 153|  void** p_first;
 154|  void** p;
 155|  int    nElem;
 156|
 157|  ERRORS_INITCHK( m, 0 );
 158|  ASSERT( ArrX_Buf_chk( buf ) && ArrX_chk( arr ) );
 159|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_size == 0 );
 160|
 161|  /* ポインタ配列のメモリ領域を確保する */
 162|  nElem = ((char*)arr->last - (char*)arr->first) / elem_size;
 163|  p_first = ArrX_Buf_allocs( buf, void*, nElem );
 164|  p = p_first;
 165|
 166|  /* アドレスをポインタ配列に格納する */
 167|  pElem_over = (char*)arr->last;
 168|  for ( pElem = (char*)arr->first; pElem < pElem_over; pElem += elem_size ) {
 169|    *p = pElem;  p++;
 170|  }
 171|
 172|  /* ポインタ配列を初期化する */
 173|  ArrX_init2( m, (void*)p_first, (void*)p );
 174|
 175|  ASSERT( ArrX_chk( m ) );
 176|}
 177|
 178|
 179| 
 180|/****************************************************************
 181|  4-5. <<< [ArrX_castFrom_ArrX_Buf_imp] ArrX 型にキャストする >>> 
 182|*****************************************************************/
 183|ArrX*  ArrX_castFrom_ArrX_Buf_imp( ArrX* arr, ArrX_Buf* buf )
 184|{
 185|  ArrX_init2( arr, buf->first, buf->last );
 186|  return  arr;
 187|}
 188|
 189| 
 190|/****************************************************************
 191|  4-6. <<< [ArrX_chk] 正規チェック >>> 
 192|*****************************************************************/
 193|int  ArrX_chk( ArrX* m )
 194|{
 195|  ERRORS_INITCHK_FOR_SUB( m, 1 );
 196|  return  m->first <= m->last;
 197|}
 198|
 199| 
 200|/****************************************************************
 201|  4-7. <<< [ArrX_getN_imp] 要素数を返す  >>> 
 202|・ArrX_getN の実装部です。(デバッグ用)
 203|*****************************************************************/
 204|int  ArrX_getN_imp( ArrX* m, int size )
 205|{
 206|  ERRORS_INITCHK( m, 1 );
 207|  ASSERT( ArrX_chk( m ) );
 208|  ASSERT( ( (char*)m->last - (char*)m->first ) % size == 0 );
 209|
 210|  return  ( (char*)m->last - (char*)m->first ) / size;
 211|}
 212|
 213| 
 214|/****************************************************************
 215|  4-8. <<< [ArrX_get_imp] 配列番号から要素を返す >>> 
 216|【引数】
 217|  ・ArrX*  m;   配列
 218|  ・int    i;      配列番号
 219|  ・int    size;   配列要素のサイズ
 220|【補足】
 221|・リリース時は、マクロ版 ArrX_get を呼び出します。
 222|*****************************************************************/
 223|void*  ArrX_get_imp( ArrX* m, int i, int size )
 224|{
 225|  void*  p = (char*)m->first + i * size;
 226|
 227|  ASSERT( p < m->last );
 228|  ASSERT( ( (char*)m->last - (char*)m->first ) % size == 0 );
 229|
 230|  return  p;
 231|}
 232|
 233|
 234| 
 235|/****************************************************************
 236|  4-9. <<< [ArrX_Able_getNext_imp] ArrX_Able_getNext の実装部 >>> 
 237|*****************************************************************/
 238|#ifdef  USES_OFFSET
 239|void*  ArrX_Able_getNext_imp( ArrX_Able* m, void* base,
 240|  int elem_size, Offset inherit )
 241|{
 242|  char*  p = (char*)base;
 243|
 244|  ASSERT( ( (char*)m->arr.last - (char*)m->arr.first ) % elem_size == 0 );
 245|
 246|  p += elem_size;
 247|  while ( p < (char*)m->arr.last ) {
 248|    if ( Offset_ref( inherit, p, ArrX_AbleElem ) )
 249|      return  (void*)p;
 250|    p += elem_size;
 251|  }
 252|  return  NULL;
 253|}
 254|#endif
 255| 
 256|/****************************************************************
 257|  4-10. <<< [ArrX_setStrs] 複数の文字列を配列に入れる >>> 
 258|【機能】
 259|・配列のすべての文字列要素を入れます。
 260|【補足】
 261|・引数 ... に指定する文字列は、配列の用素数だけ指定します。
 262|  それより多くても少なくてもいけません。
 263|  ArrX_init( &aa, buf, sizeof(char*)*3 ); のように、
 264|  用素数を調整してください。
 265|*****************************************************************/
 266|#ifdef  STDLIBS_INCLUDE_STDARG_H
 267|void  ArrX_setStrs( ArrX* m, ... )
 268|{
 269|  va_list  va;
 270|  char**   p;
 271|
 272|  va_start( va, m );
 273|
 274|  for ( p = (char**)m->first; p < (char**)m->last; p++ )
 275|    *p = va_arg( va, char* );
 276|
 277|  va_end( va );
 278|}
 279|#endif
 280|
 281|
 282| 
 283|/***********************************************************************
 284|  4-11. <<< [ArrX_memrot_imp] 配列の要素をローテーションする >>> 
 285|【引数】
 286|  ・void*  ball;     配列の要素へのアドレス
 287|  ・void*  target;   要素の移動先のアドレス
 288|  ・void*  work;     ワーク領域(配列の要素の型の変数へのアドレス)
 289|  ・int  ball_size;  要素のメモリサイズ
 290|【補足】
 291|・ArrX_memrot の実装部です。
 292|************************************************************************/
 293|void  ArrX_memrot_imp( void* ball, void* target, void* work, int ball_size )
 294|{
 295|  memcpy( work, ball, ball_size );
 296|  if ( ball > target ) {
 297|    memmove( (char*)target + ball_size, target,
 298|      (char*)ball - (char*)target );
 299|  }
 300|  else {
 301|    memmove( ball, (char*)ball + ball_size,
 302|      (char*)target - (char*)ball );
 303|  }
 304|  memcpy( target, work, ball_size );
 305|}
 306|
 307| 
 308|/***********************************************************************
 309|  4-12. <<< [ArrX_print] 配列の要素をデバッグ表示する >>> 
 310|【引数】
 311|  ・ArrX*  m;     配列
 312|  ・char*  types;    型リスト
 313|【補足】
 314|・型リストは、配列要素の型を次の文字で指定した文字列です。
 315|    ・'i' ... 整数型(int)
 316|    ・'s' ... 文字列型(char*)
 317|    ・'p' ... アドレス型(void*)
 318|  整数と文字列が1つずつ入った構造体の場合は、"is" と指定します。
 319|************************************************************************/
 320|#ifdef  USES_ERRORS
 321|#ifndef  ERRORS_CUT_DEBUG_TOOL
 322|void  ArrX_print( ArrX* m, char* types )
 323|{
 324|  char*  t = types;
 325|  int*   p;
 326|  int    i = 0;
 327|
 328|  for ( ArrX_forEach( m, &p, int ) ) {
 329|    switch ( *t ) {
 330|      case 'i':
 331|        Errors_printf( "  [%d] = %d (0x%X) '%c'", i, *p, *p, *p );
 332|        break;
 333|      case 's':
 334|        Errors_printf( "  [%d] = (%p) \"%s\"", i, *p, *p );
 335|        break;
 336|      case 'p':
 337|        Errors_printf( "  [%d] = (%p)", i, *p );
 338|        break;
 339|      default:
 340|        error();
 341|    }
 342|    t++;  if ( *t == '\0' )   t = types;
 343|    i++;
 344|  }
 345|}
 346|#endif
 347|#endif
 348| 
 349|/**************************************************************************
 350|  4-13. <<< [ArrX_search_i_imp] int 型のキーを用いて線形検索する >>> 
 351|・この関数は、ArrX_search_i マクロの実装部です。
 352|***************************************************************************/
 353|#ifdef USES_OFFSET
 354|void* ArrX_search_i_imp( ArrX* m, Offset_Key* key, int val,
 355|  int elem_sizeof )
 356|{
 357|  ASSERT( ArrX_chk( m ) && Offset_Key_chk( key ) );
 358|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
 359|
 360|  return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 361|           &val, key->offset, 0, sizeof(int) );
 362|}
 363|#endif /* USES_OFFSET */
 364|
 365|
 366| 
 367|/**************************************************************************
 368|  4-14. <<< [ArrX_search_d_imp] double 型のキーを用いて線形検索する >>> 
 369|・この関数は、ArrX_search_d マクロの実装部です。
 370|***************************************************************************/
 371|#ifdef USES_OFFSET
 372|void* ArrX_search_d_imp( ArrX* m, Offset_Key* key, double val,
 373|  int elem_sizeof )
 374|{
 375|  ASSERT( ArrX_chk( m ) && Offset_Key_chk( key ) );
 376|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
 377|
 378|  return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 379|           &val, key->offset, 0, sizeof(double) );
 380|}
 381|#endif /* USES_OFFSET */
 382|
 383|
 384| 
 385|/**************************************************************************
 386|  4-15. <<< [ArrX_search_s_imp] 文字列型のキーを用いて線形検索する >>> 
 387|・この関数は、ArrX_search_s マクロの実装部です。
 388|***************************************************************************/
 389|#ifdef USES_OFFSET
 390|void* ArrX_search_s_imp( ArrX* m, Offset_Key* key, const char* val,
 391|  int elem_sizeof )
 392|{
 393|  ASSERT( ArrX_chk( m ) && Offset_Key_chk( key ) );
 394|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
 395|
 396|  if ( key->type == Offset_CString )
 397|    return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 398|             val, key->offset, 0, -1 );
 399|  else if ( key->type == Offset_CStringP || key->type == Offset_StrV ) {
 400|    return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 401|             val, key->offset, 1, -1 );
 402|  }
 403|  #ifndef ARRX_NO_STRICMP
 404|    else if ( key->type == Offset_CStringPI ) {
 405|      return  ArrX_Imp_linearSearchF( m->first, m->last, (int)elem_sizeof,
 406|             val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpIStr );
 407|    }
 408|  #endif
 409|  else {
 410|    ASSERT( key->type == Offset_CStringPW );
 411|    #ifdef USES_STRX
 412|	  return  ArrX_Imp_linearSearchF( m->first, m->last, (int)elem_sizeof,
 413|               val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpMatchMask );
 414|    #else
 415|      Errors_notSupport();
 416|      return  NULL;  /* dummy */
 417|    #endif
 418|  }
 419|}
 420|#endif /* USES_OFFSET */
 421|
 422|
 423| 
 424|/**************************************************************************
 425|  4-16. <<< [ArrX_search_ps_imp] 文字列型のキーを用いて線形検索する >>> 
 426|・この関数は、ArrX_search_ps マクロの実装部です。
 427|***************************************************************************/
 428|#ifdef USES_OFFSET
 429|void* ArrX_search_ps_imp( ArrX* m, Offset_Key* key, const char* val )
 430|{
 431|  ASSERT( ArrX_chk( m ) && Offset_Key_chk( key ) );
 432|
 433|  if ( key->type == Offset_CString )
 434|    return  ArrX_Imp_linearSearchP( (void**)m->first, (void**)m->last,
 435|             val, key->offset, 0, -1 );
 436|  else if ( key->type == Offset_CStringP ) {
 437|    return  ArrX_Imp_linearSearchP( (void**)m->first, (void**)m->last,
 438|             val, key->offset, 1, -1 );
 439|  }
 440|  #ifndef ARRX_NO_STRICMP
 441|    else if ( key->type == Offset_CStringPI ) {
 442|      return  ArrX_Imp_linearSearchPF( (void**)m->first, (void**)m->last,
 443|             val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpIStr );
 444|    }
 445|  #endif
 446|  else {
 447|    ASSERT( key->type == Offset_CStringPW );
 448|    #ifdef USES_STRX
 449|	  return  ArrX_Imp_linearSearchPF( (void**)m->first, (void**)m->last,
 450|               val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpMatchMask );
 451|    #else
 452|      Errors_notSupport();
 453|      return  NULL;  /* dummy */
 454|    #endif
 455|  }
 456|}
 457|#endif /* USES_OFFSET */
 458|
 459| 
 460|/**************************************************************************
 461|  4-17. <<< [ArrX_doLoopFunc] SYM_STRUCT_LOOP_FUNC に指定する関数 >>> 
 462|***************************************************************************/
 463|#ifdef  USES_SYM
 464|bool  ArrX_doLoopFunc( Sym_Ref* container, Sym_Ref* elem )
 465|{
 466|  ArrX*  m;
 467|
 468|  if ( container->type == Sym_StructType )  m = (ArrX*)container->adr;
 469|  else  m = *(ArrX**)container->adr;
 470|
 471|  if ( elem->adr == NULL )  elem->adr = m->first;
 472|  else {
 473|    if ( elem->type == Sym_StructTypeP )
 474|      elem->adr = (void*)( (char*)elem->adr + sizeof(void*) );
 475|    else
 476|      elem->adr = (void*)( (char*)elem->adr + (int)container->elem_param );
 477|  }
 478|
 479|  return  elem->adr < m->last;
 480|}
 481|#endif
 482|
 483| 
 484|/*-------------------------------------------------------------------------*/
 485|/* ◆5. <<<< バッファ (ArrX_Buf) >>>> */ 
 486|/*-------------------------------------------------------------------------*/
 487|
 488|#ifdef  USES_SYM
 489|SYM_STRUCT_START( ArrX_Buf )
 490|SYM_STRUCT_LOOP_FUNC( ArrX_Buf, ArrX_Buf_doLoopFunc )
 491|SYM_STRUCT_MEMB( ArrX_Buf, void*, first )
 492|SYM_STRUCT_MEMB( ArrX_Buf, void*, last )
 493|SYM_STRUCT_END( ArrX_Buf )
 494|#endif
 495| 
 496|/***********************************************************************
 497|  5-1. <<< ツリー構造におけるコンテナ >>> 
 498|
 499|【メモ】(作成中)
 500|
 501|  
 502|
 503| ツリーにノードを追加する関数とツリーからノードを削除する関数のうち、
 504| インターフェイスとして必要な最低限の関数がどれか分析することで
 505| より単純で効率のよいコンテナの種類を使うことが出来ます。
 506|
 507| 入力データにおいて、同じ親のノードが一個所に集まっている
 508| (親ノードが所有する子ノードが十分揃っている)(シーケンシャル)
 509| かどうかを分析することでも、より単純で効率のよいコンテナの種類を
 510| 使うことが出来ます。
 511|
 512| コンテナは、シーケンシャル・タイプとランダム・タイプがあります。
 513| シーケンシャル・タイプは、ArrX ArrX_Buf の組み合わせ、
 514| ランダム・レングス・タイプは ArrX2 コンポーネント(予定)が
 515| あります。
 516|
 517| ツリーのリンク(関連)は、子配列タイプと、子ポインタ・タイプと、
 518| 親ポインタ・タイプがあります。
 519| ・子配列タイプは、子ノードをメモリ的に連続させる必要があるので、
 520|   分配方法に工夫が必要になります。(静的データは除く)
 521|   シーケンシャル・タイプとランダム・レングス・タイプ
 522| ・子ポインタ・タイプは、子ノードをリスト構造でつなげます。
 523|   ランダム・タイプ(例:ArrayU3)があります。
 524|   リスト構造でなく、使用/未使用または ID の配列でも構いません。
 525| ・親ポインタ・タイプは、親ノードへのポインタを持ちます。
 526|   ただし、対応づけが逆なので後で検索が必要になります。
 527|
 528| ノードを削除する関数を決めることで、メモリ管理の配置位置が
 529| 決まります。削除するノードのうち、最も子の方のノードには、
 530| シーケンシャル・タイプをメンバに持たせます。そして、
 531| その親のノードには、ランダム・タイプをメンバに持たせて、
 532| 子ノードを削除できるようにします。
 533|
 534| ノードを削除ではなく再初期化する(再利用する領域を明示的に指定する)
 535| 関数を決めた場合、親のノードには、シーケンシャル・タイプを
 536| メンバに持たせることが出来ます。ただし、再初期化しても
 537| メモリサイズを変更することはできません。変更する場合は、
 538| 更に親のノードを削除するか再初期化して、
 539| メモリサイズの設定を初めからやり直してください。
 540|
 541| シーケンシャルでなくても、子ポインタ・タイプや
 542| 親ポインタ・タイプの場合、
 543| シーケンシャル・タイプをメンバに持たせることが出来ます。
 544|
 545| 十分性が有れば、更に親の十分性も検討することが出来ます。
 546| ランダム・レングス・タイプを使った場合、それより親のノードは
 547| 必ずランダム・レングス・タイプにしなければなりません。
 548|
 549| ノードを追加する関数は、必要に応じて親ノードへの参照や
 550| メモリ管理を引数に指定するようにします。
 551| ノードを追加する関数の内部では、そのノードより子の方のノード
 552| を追加する場合、追加するノードより親の方にあるメモリ管理から
 553| 領域を確保します。
 554|
 555| 対多関連をシーケンシャルにすれば階層ごとにバッファを用意すればよい
 556| シーケンシャルは抽象クラスでもよい(クラスIDが必要だが)
 557|************************************************************************/
 558|
 559|
 560| 
 561|/****************************************************************
 562|  5-2. <<< [ArrX_Buf_init] 初期化する >>> 
 563|【補足】
 564|・初期化するとバッファは空になります。
 565|*****************************************************************/
 566|void  ArrX_Buf_init( ArrX_Buf* m, void* mem, int mem_sizeof )
 567|{
 568|  ERRORS_INITCHK( m, 0 );
 569|
 570|  m->first = mem;
 571|  m->last = mem;
 572|  m->bufLast = (char*)mem + mem_sizeof;
 573|
 574|  ASSERT( ArrX_Buf_chk( m ) );
 575|}
 576|
 577|
 578| 
 579|/****************************************************************
 580|  5-3. <<< [ArrX_Buf_inits] 複数のバッファを初期化する >>> 
 581|【引数】
 582|  ・void*  mem;     メモリ領域(サイズは ArrX_Buf_getMemSize より)
 583|  ・int*   ms;      最大要素数が格納されている配列
 584|  ・int    n;       初期化するバッファの数
 585|  ・...             バッファ1、要素サイズ1、バッファ2、要素サイズ2...
 586|  ・void*  返り値;  使用しなかったメモリ領域の先頭アドレス
 587|【補足】
 588|・mem を各バッファに割り振ります。
 589|・... には、初期化するバッファと要素サイズを複数並べます。
 590|  バッファは ArrX_Buf* 型、要素サイズは int 型です。
 591|・初期化するとバッファは空になります。
 592|【例】
 593| next = ArrX_Buf_inits( mem, ms, 3,
 594|   &m->polys, sizeof(Pdo_Poly),
 595|   &m->materials, sizeof(Pdo_Material),
 596|   &m->points, sizeof(Pdo_Point) );
 597|*****************************************************************/
 598|#ifdef  STDLIBS_INCLUDE_STDARG_H
 599|void*  ArrX_Buf_inits( void* mem, int* ms, int n, ... )
 600|{
 601|  int  i;
 602|  va_list  va;
 603|  ArrX_Buf*  buf;
 604|  int   size;
 605|
 606|  va_start( va, n );
 607|
 608|  for ( i = 0; i < n; i++ ) {
 609|    buf = va_arg( va, ArrX_Buf* );
 610|    size = *ms * va_arg( va, int );
 611|    ArrX_Buf_init( buf, mem, size );
 612|    mem = (void*)( (char*)mem + size );
 613|    ms ++;
 614|  }
 615|
 616|  va_end( va );
 617|
 618|  return  mem;
 619|}
 620|#endif
 621|
 622| 
 623|/****************************************************************
 624|  5-4. <<< [ArrX_Buf_getMemSize] 必要なメモリサイズを返す >>> 
 625|【引数】
 626|  ・int*   ms;      最大要素数が格納されている配列
 627|  ・int    n;       初期化するバッファの数
 628|  ・...             要素サイズ1、要素サイズ2...
 629|  ・int    返り値;  必要なメモリサイズ
 630|【補足】
 631|・ArrX_Buf_inits の引数に指定するメモリ領域に必要なメモリサイズを
 632|  計算します。
 633|【例】
 634| size = ArrX_Buf_getMemSize( ms, 3,
 635|   sizeof(Pdo_Poly), sizeof(Pdo_Material), sizeof(Pdo_Point) );
 636|*****************************************************************/
 637|#ifdef  STDLIBS_INCLUDE_STDARG_H
 638|int  ArrX_Buf_getMemSize( int* ms, int n, ... )
 639|{
 640|  int  i;
 641|  int  ret = 0;
 642|  va_list  va;
 643|
 644|  va_start( va, n );
 645|
 646|  for ( i = 0; i < n ; i++ ) {
 647|    ret += va_arg( va, int ) * (*ms);
 648|    ms++;
 649|  }
 650|
 651|  va_end( va );
 652|
 653|  return  ret;
 654|}
 655|#endif
 656|
 657| 
 658|/****************************************************************
 659|  5-5. <<< [ArrX_Buf_chk] 正規チェック >>> 
 660|*****************************************************************/
 661|int  ArrX_Buf_chk( ArrX_Buf* m )
 662|{
 663|  ERRORS_INITCHK_FOR_SUB( m, 1 );
 664|  return  m->first <= m->last &&
 665|          m->first <= m->bufLast &&
 666|          m->last <= m->bufLast;
 667|}
 668|
 669| 
 670|/****************************************************************
 671|  5-6. <<< [ArrX_Buf_get_imp] 配列番号から要素を返す >>> 
 672|【引数】
 673|  ・ArrX*  m;   配列
 674|  ・int    i;      配列番号
 675|  ・int    size;   配列要素のサイズ
 676|【補足】
 677|・リリース時は、マクロ版 ArrX_Buf_get を呼び出します。
 678|*****************************************************************/
 679|void*  ArrX_Buf_get_imp( ArrX_Buf* m, int i, int size )
 680|{
 681|  void*  p = (char*)m->first + i * size;
 682|
 683|  ASSERT( p < m->last );
 684|  ASSERT( ( (char*)m->last - (char*)m->first ) % size == 0 );
 685|
 686|  return  p;
 687|}
 688|
 689|
 690| 
 691|/**************************************************************************
 692|  5-7. <<< [ArrX_Buf_alloc_imp] 指定サイズのバッファをアロケートする >>> 
 693|【引数】
 694|  ・int  alloc_sizeof;  要素のサイズ
 695|  ・void*  返り値;         確保した領域の先頭アドレス
 696|【補足】
 697|・alloc_sizeof のサイズのメモリ領域を確保(アロケート)して、
 698|  その先頭アドレスを返します。
 699|・アロケートしたら、メモリ領域( m->first から m->bufLast まで)
 700|  を超えてしまう場合(メモリ不足の場合)、error 関数を呼び出します。
 701|・この関数は、ArrX_Buf_alloc マクロの実装部です。
 702|***************************************************************************/
 703|void*  ArrX_Buf_alloc_imp( ArrX_Buf* m, int alloc_sizeof )
 704|{
 705|  void*  ret = m->last;
 706|  void*  nextLast = (char*)m->last + alloc_sizeof;
 707|
 708|  ASSERT( ArrX_Buf_chk( m ) );
 709|  if ( nextLast > m->bufLast ) {
 710|    #if !defined(NDEBUG) && !defined(ERRORS_CUT_DEBUG_TOOL)
 711|      ArrX_Buf_printElem( m, char, "" );
 712|    #endif
 713|    error2_0( ArrX_Err_Full, "バッファが満杯です" );
 714|  }
 715|
 716|  /* メモリ領域を確保する */
 717|  m->last = nextLast;
 718|
 719|  ASSERT( ArrX_Buf_chk( m ) );
 720|
 721|  return  ret;
 722|}
 723|
 724|
 725| 
 726|/**************************************************************************
 727|  5-8. <<< [ArrX_Buf_allocs_imp] 指定サイズのバッファを複数アロケートする >>> 
 728|【引数】
 729|  ・int  alloc_sizeof;  要素1つのサイズ
 730|  ・int  nElem;            要素の数
 731|  ・void*  返り値;         確保した領域の先頭アドレス
 732|【補足】
 733|・alloc_sizeof * nElem のサイズのメモリ領域を確保(アロケート)して、
 734|  その先頭アドレスを返します。
 735|・アロケートしたら、メモリ領域( m->first から m->bufLast まで)
 736|  を超えてしまう場合(メモリ不足の場合)、error 関数を呼び出します。
 737|・この関数は、ArrX_Buf_allocs マクロの実装部です。
 738|***************************************************************************/
 739|void*  ArrX_Buf_allocs_imp( ArrX_Buf* m, int alloc_sizeof, int nElem )
 740|{
 741|  void*  ret = m->last;
 742|  void*  nextLast = (char*)m->last + alloc_sizeof * nElem;
 743|
 744|  ASSERT( ArrX_Buf_chk( m ) );
 745|  if ( nextLast > m->bufLast )
 746|     error2_0( ArrX_Err_Full, "バッファが満杯です" );
 747|
 748|  /* メモリ領域を確保する */
 749|  m->last = nextLast;
 750|
 751|  ASSERT( ArrX_Buf_chk( m ) );
 752|
 753|  return  ret;
 754|}
 755|
 756|
 757| 
 758|/****************************************************************
 759|  5-9. <<< [ArrX_Buf_addCopy] バッファに追加する >>> 
 760|【引数】
 761|  ・ArrX* plus;  追加するデータまたは配列へのポインタ
 762|【補足】
 763|・plus は、単一のデータでも配列でも構いません。
 764|・単一のデータの場合、plus->first = ptr,plus->last = ptr+1 と
 765|  して引数に渡します。
 766|*****************************************************************/
 767|void  ArrX_Buf_addCopy( ArrX_Buf* m, ArrX* plus )
 768|{
 769|  int   plus_size = (char*)plus->last - (char*)plus->first;
 770|
 771|  ASSERT( ArrX_Buf_chk( m ) && ArrX_chk( plus ) );
 772|  if ( m->last >= m->bufLast ) {
 773|    char  s1[20], s2[20];
 774|    strncpy( s1, (char*)m->first, sizeof(s1)-1 );  s1[19] = '\0';
 775|    strncpy( s2, (char*)m->last-19, sizeof(s2)-1 );  s2[19] = '\0';
 776|    Errors_printf_release( "バッファが満杯です\n%s 〜 %s", s1, s2 );
 777|    error2_0( ArrX_Err_Full, "バッファが満杯です" );
 778|  }
 779|
 780|  /* バッファに余裕がある場合、*/
 781|  if ( (char*)m->last + plus_size <= (char*)m->bufLast ) {
 782|    memcpy( m->last, plus->first, plus_size );
 783|    m->last = (void*)((char*)m->last + plus_size);
 784|  }
 785|
 786|  /* バッファに一部しか入らない場合、*/
 787|  else {
 788|    memcpy( m->last, plus->first,
 789|            (char*)m->bufLast - (char*)m->last );
 790|    m->last = m->bufLast;
 791|  }
 792|
 793|  ASSERT( ArrX_Buf_chk( m ) );
 794|}
 795|
 796|
 797| 
 798|/****************************************************************
 799|  5-10. <<< [ArrX_Buf_addChr] バッファに1バイト追加する >>> 
 800|【引数】
 801|  ・unsigned char c;  追加するデータ
 802|*****************************************************************/
 803|void  ArrX_Buf_addChr( ArrX_Buf* m, unsigned char c )
 804|{
 805|  ASSERT( ArrX_Buf_chk( m ) );
 806|
 807|  /* バッファが満杯の場合、バッファの最後に追加する */
 808|  if ( m->last == m->bufLast )
 809|    m->last = (void*)((unsigned char*)m->last - 1);
 810|
 811|  /* バッファに余裕がある場合、*/
 812|  *(unsigned char*)m->last = c;
 813|  m->last = (void*)((unsigned char*)m->last + 1);
 814|
 815|  ASSERT( ArrX_Buf_chk( m ) );
 816|}
 817|
 818|
 819| 
 820|/****************************************************************
 821|  5-11. <<< [ArrX_Buf_addStr] バッファに文字列を追加する >>> 
 822|【引数】
 823|  ・char* s;  追加するデータ
 824|【補足】
 825|・strcat と同じような機能です。
 826|・バッファの内容の最後には、'\0' が付いています。ただし、一度も
 827|  本関数を呼ばなかったときは、付いていないので、一度、空文字を
 828|  追加しておいてください。
 829|*****************************************************************/
 830|void  ArrX_Buf_addStr( ArrX_Buf* m, const char* s )
 831|{
 832|  int  left = (char*)m->bufLast - (char*)m->last;
 833|  int  s_len = strlen( s );
 834|
 835|  if ( s_len < left ) {
 836|    strcpy( (char*)m->last, s );
 837|    m->last = (char*)m->last + s_len;
 838|  }
 839|  else {
 840|    *( (char*)m->bufLast - 1 ) = '\0';
 841|    strncpy( (char*)m->last, s, left - 1 );
 842|    m->last = m->bufLast;
 843|  }
 844|}
 845|
 846| 
 847|/****************************************************************
 848|  5-12. <<< [ArrX_Buf_addMem] バッファにデータを追加する >>> 
 849|【引数】
 850|  ・char* s;       追加するデータの先頭アドレス
 851|  ・char* s_size;  追加するデータのサイズ
 852|【補足】
 853|・strcat と同じような機能ですが、最後(*s_over)に '\0' は付きません。
 854|・容量が足りないときは、入れられる分だけ入れます。
 855|*****************************************************************/
 856|void  ArrX_Buf_addMem( ArrX_Buf* m, const void* s,
 857|  int s_size )
 858|{
 859|  int  left = (char*)m->bufLast - (char*)m->last;
 860|
 861|  if ( s_size <= left ) {
 862|    memcpy( m->last, s, s_size );
 863|    m->last = (char*)m->last + s_size;
 864|  }
 865|  else {
 866|    memcpy( m->last, s, left );
 867|    m->last = m->bufLast;
 868|  }
 869|}
 870|
 871| 
 872|/*********************************************************************
 873|  5-13. <<< [ArrX_Buf_addEndOfC] バッファに文字列の終端文字を追加する >>> 
 874|【補足】
 875|・バッファが満杯の場合、バッファの最後の1バイトに入っていたデータの
 876|  代わりに終端文字 '\0' を入れます。
 877|**********************************************************************/
 878|void  ArrX_Buf_addEndOfC( ArrX_Buf* m )
 879|{
 880|  ASSERT( ArrX_Buf_chk( m ) );
 881|
 882|  /* バッファが満杯の場合、*/
 883|  if ( m->last == m->bufLast ) {
 884|    *((unsigned char*)m->last - 1) = '\0';
 885|  }
 886|
 887|  /* バッファに余裕がある場合、*/
 888|  else {
 889|    *(unsigned char*)m->last = '\0';
 890|    m->last = (void*)((unsigned char*)m->last + 1);
 891|  }
 892|
 893|  ASSERT( ArrX_Buf_chk( m ) );
 894|}
 895|
 896|
 897| 
 898|/**************************************************************************
 899|  5-14. <<< [ArrX_Buf_getLast_f_imp] ArrX_Buf_getLast_f の実装部 >>> 
 900|***************************************************************************/
 901|void*  ArrX_Buf_getLast_f_imp( ArrX_Buf* m, int size )
 902|{
 903|  ASSERT( m->first != m->last );  /* 要素数が0では使用できません */
 904|
 905|  return  (char*)(m->last) - size;
 906|}
 907| 
 908|/**************************************************************************
 909|  5-15. <<< [ArrX_Buf_free_imp] 指定サイズのバッファを解放する >>> 
 910|【引数】
 911|  ・void*  p;          解放する領域の先頭アドレス
 912|  ・int  free_sizeof;  要素のサイズ
 913|【補足】
 914|・新しい領域(末尾)から順番に解放すれば、素早く解放することも出来ます。
 915|・領域の途中を開放したときは、その部分より後の領域を手前に詰めます。
 916|・この関数は、ArrX_Buf_free マクロの実装部です。
 917|***************************************************************************/
 918|void  ArrX_Buf_free_imp( ArrX_Buf* m, void* p, int free_sizeof )
 919|{
 920|  void*  nextLast = (char*)m->last - free_sizeof;
 921|
 922|  ASSERT( ArrX_Buf_chk( m ) );
 923|
 924|  /* メモリの途中を開放する */
 925|  if ( nextLast != p ) {
 926|    ASSERT( (char*)p >= (char*)m->first && (char*)p < (char*)m->last );
 927|    memcpy( p, (char*)p + free_sizeof, (char*)m->last - ((char*)p + free_sizeof) );
 928|  }
 929|
 930|  /* メモリ領域の末尾を解放する */
 931|  m->last = nextLast;
 932|
 933|  ASSERT( ArrX_Buf_chk( m ) );
 934|}
 935|
 936|
 937| 
 938|/**************************************************************************
 939|  5-16. <<< [ArrX_Buf_search_i_imp] int 型のキーを用いて線形検索する >>> 
 940|・この関数は、ArrX_Buf_search_i マクロの実装部です。
 941|***************************************************************************/
 942|#ifdef USES_OFFSET
 943|void* ArrX_Buf_search_i_imp( ArrX_Buf* m, Offset_Key* key, int val,
 944|  int elem_sizeof )
 945|{
 946|  ASSERT( ArrX_Buf_chk( m ) && Offset_Key_chk( key ) );
 947|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
 948|
 949|  return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 950|           &val, key->offset, 0, sizeof(int) );
 951|}
 952|#endif /* USES_OFFSET */
 953|
 954|
 955| 
 956|/**************************************************************************
 957|  5-17. <<< [ArrX_Buf_search_d_imp] double 型のキーを用いて線形検索する >>> 
 958|・この関数は、ArrX_Buf_search_d マクロの実装部です。
 959|***************************************************************************/
 960|#ifdef USES_OFFSET
 961|void* ArrX_Buf_search_d_imp( ArrX_Buf* m, Offset_Key* key, double val,
 962|  int elem_sizeof )
 963|{
 964|  ASSERT( ArrX_Buf_chk( m ) && Offset_Key_chk( key ) );
 965|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
 966|
 967|  return  ArrX_Imp_linearSearch( m->first, m->last, (int)elem_sizeof,
 968|           &val, key->offset, 0, sizeof(double) );
 969|}
 970|#endif /* USES_OFFSET */
 971|
 972|
 973| 
 974|/**************************************************************************
 975|  5-18. <<< [ArrX_Buf_search_s_imp] ArrX_Buf_search_s マクロの実装部 >>> 
 976|【補足】
 977|・start は、検索を開始する最初の要素です。最初から検索するときは、
 978|  m->first, 前回の検索結果の続きを検索するときは、p+1(p はポインタ)を
 979|  指定します。
 980|***************************************************************************/
 981|#ifdef USES_OFFSET
 982|void* ArrX_Buf_search_s_imp( ArrX_Buf* m, void* start, Offset_Key* key,
 983|  const char* val, int elem_sizeof )
 984|{
 985|  ASSERT( ArrX_Buf_chk( m ) && Offset_Key_chk( key ) );
 986|  ASSERT( ( (char*)m->last - (char*)start ) % elem_sizeof == 0 );
 987|
 988|  if ( key->type == Offset_CString )
 989|    return  ArrX_Imp_linearSearch( start, m->last, (int)elem_sizeof,
 990|             val, key->offset, 0, -1 );
 991|  else if ( key->type == Offset_CStringP || key->type == Offset_StrV ) {
 992|    return  ArrX_Imp_linearSearch( start, m->last, (int)elem_sizeof,
 993|             val, key->offset, 1, -1 );
 994|  }
 995|  #ifndef ARRX_NO_STRICMP
 996|    else if ( key->type == Offset_CStringPI ) {
 997|      return  ArrX_Imp_linearSearchF( start, m->last, (int)elem_sizeof,
 998|             val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpIStr );
 999|    }
1000|  #endif
1001|  else {
1002|    ASSERT( key->type == Offset_CStringPW );
1003|    #ifdef USES_STRX
1004|	  return  ArrX_Imp_linearSearchF( start, m->last, (int)elem_sizeof,
1005|               val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpMatchMask );
1006|    #else
1007|      Errors_notSupport();
1008|      return  NULL;  /* dummy */
1009|    #endif
1010|  }
1011|}
1012|#endif /* USES_OFFSET */
1013|
1014|
1015| 
1016|/**************************************************************************
1017|  5-19. <<< [ArrX_Buf_search_ps_imp] 文字列型のキーを用いて線形検索する >>> 
1018|・この関数は、ArrX_Buf_search_ps マクロの実装部です。
1019|***************************************************************************/
1020|#ifdef USES_OFFSET
1021|void* ArrX_Buf_search_ps_imp( ArrX_Buf* m, Offset_Key* key, const char* val )
1022|{
1023|  ASSERT( ArrX_Buf_chk( m ) && Offset_Key_chk( key ) );
1024|
1025|  if ( key->type == Offset_CString )
1026|    return  ArrX_Imp_linearSearchP( (void**)m->first, (void**)m->last,
1027|             val, key->offset, 0, -1 );
1028|  else if ( key->type == Offset_CStringP ) {
1029|    return  ArrX_Imp_linearSearchP( (void**)m->first, (void**)m->last,
1030|             val, key->offset, 1, -1 );
1031|  }
1032|  #ifndef ARRX_NO_STRICMP
1033|    else if ( key->type == Offset_CStringPI ) {
1034|      return  ArrX_Imp_linearSearchPF( (void**)m->first, (void**)m->last,
1035|             val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpIStr );
1036|    }
1037|  #endif
1038|  else {
1039|    ASSERT( key->type == Offset_CStringPW );
1040|    #ifdef USES_STRX
1041|	  return  ArrX_Imp_linearSearchPF( (void**)m->first, (void**)m->last,
1042|               val, key->offset, NULL, (ArrX_CmpF)ArrX_Imp_cmpMatchMask );
1043|    #else
1044|      Errors_notSupport();
1045|      return  NULL;  /* dummy */
1046|    #endif
1047|  }
1048|}
1049|#endif /* USES_OFFSET */
1050|
1051| 
1052|/**************************************************************************
1053|  5-20. <<< [ArrX_Buf_print_imp] 内部状態を表示する >>> 
1054|***************************************************************************/
1055|#ifndef  ERRORS_CUT_DEBUG_TOOL
1056|void  ArrX_Buf_print_imp( ArrX_Buf* m, const char* title )
1057|{
1058|  ERRORS_INITCHK( m, 1 );
1059|
1060|  Errors_printf( "%sArrX_Buf(%p) : first = %p, last = %p, bufLast = %p", title,
1061|    m, m->first, m->last, m->bufLast );
1062|}
1063|#endif
1064|
1065| 
1066|/**************************************************************************
1067|  5-21. <<< [ArrX_Buf_printElem_imp] 内部状態を表示する >>> 
1068|***************************************************************************/
1069|#ifndef  ERRORS_CUT_DEBUG_TOOL
1070|void  ArrX_Buf_printElem_imp( ArrX_Buf* m, int elem_sizeof, const char* title )
1071|{
1072|  int  size = (char*)m->last - (char*)m->first;
1073|  int  bufSize = (char*)m->bufLast - (char*)m->first;
1074|
1075|  ERRORS_INITCHK( m, 1 );
1076|  ASSERT( ( (char*)m->last - (char*)m->first ) % elem_sizeof == 0 );
1077|
1078|  Errors_printf( "%sArrX_Buf(%p) : first = %p, last = %p, bufLast = %p", title,
1079|    m, m->first, m->last, m->bufLast );
1080|  if ( elem_sizeof == 1 ) {
1081|    Errors_printf( "%ssize = %d/%d", title, size, bufSize );
1082|  }
1083|  else {
1084|    Errors_printf( "%ssize = %d/%d count = %d/%d", title,
1085|      size, bufSize, size/elem_sizeof, bufSize/elem_sizeof );
1086|  }
1087|}
1088|#endif
1089|
1090| 
1091|/**************************************************************************
1092|  5-22. <<< [ArrX_Buf_print2] 配列の要素をデバッグ表示する >>> 
1093|【補足】
1094|・詳細は、ArrX_print 関数を参照してください。
1095|***************************************************************************/
1096|#ifdef  USES_ERRORS
1097|#ifndef  ERRORS_CUT_DEBUG_TOOL
1098|void  ArrX_Buf_print2( ArrX_Buf* m, char* types )
1099|{
1100|  ArrX  arr;
1101|
1102|  ArrX_castFrom_ArrX_Buf( &arr, m );
1103|  ArrX_print( &arr, types );
1104|}
1105|#endif
1106|#endif
1107| 
1108|/**************************************************************************
1109|  5-23. <<< [ArrX_Buf_doLoopFunc] SYM_STRUCT_LOOP_FUNC に指定する関数 >>> 
1110|***************************************************************************/
1111|#ifdef  USES_SYM
1112|bool  ArrX_Buf_doLoopFunc( Sym_Ref* container, Sym_Ref* elem )
1113|{
1114|  ArrX_Buf*  m;
1115|
1116|  if ( container->type == Sym_StructType )  m = (ArrX_Buf*)container->adr;
1117|  else  m = *(ArrX_Buf**)container->adr;
1118|
1119|  if ( elem->adr == NULL )  elem->adr = m->first;
1120|  else {
1121|    if ( elem->type == Sym_StructTypeP )
1122|      elem->adr = (void*)( (char*)elem->adr + sizeof(void*) );
1123|    else
1124|      elem->adr = (void*)( (char*)elem->adr + (int)container->elem_param );
1125|  }
1126|
1127|  return  elem->adr < m->last;
1128|}
1129|#endif
1130|
1131| 
1132|/*-------------------------------------------------------------------------*/
1133|/* ◆6. <<<< (ArrX_Able) 有効フラグ付き配列 >>>> */ 
1134|/*-------------------------------------------------------------------------*/
1135|
1136|
1137| 
1138|/****************************************************************
1139|  6-1. <<< [ArrX_Able_init_imp] 初期化する(すべての要素を無効にする) >>> 
1140|【引数】
1141|  ・int  arr_size;  全要素のデータのサイズ (byte)
1142|【補足】
1143|・ArrX_Able_init の実装部です。(本関数は内部用です)
1144|*****************************************************************/
1145|#ifdef  USES_OFFSET
1146|void  ArrX_Able_init_imp( ArrX_Able* m, void* arr_adr, int arr_size,
1147|  int elem_size, Offset ofsFlag )
1148|{
1149|  char*  p;
1150|  ERRORS_INITCHK( m, 0 );
1151|  ASSERT( arr_size % elem_size == 0 );
1152|
1153|  ArrX_init( &m->arr, arr_adr, arr_size );
1154|
1155|  for ( p = (char*)m->arr.first; p < (char*)m->arr.last;
1156|       p += elem_size ) {
1157|
1158|    Offset_ref( ofsFlag, p, bool ) = false;
1159|  }
1160|}
1161|#endif
1162| 
1163|/***********************************************************************
1164|  6-2. <<< [ArrX_Able_getN_imp] 有効な要素数を返す >>> 
1165|【補足】
1166|・ArrX_Able_getN の実装部です。(本関数は内部用です)
1167|************************************************************************/
1168|#ifdef  USES_OFFSET
1169|int  ArrX_Able_getN_imp( ArrX_Able* m, int elem_size, Offset ofsFlag )
1170|{
1171|  char*  p;
1172|  int  n = 0;
1173|  ERRORS_INITCHK( m, 1 );
1174|
1175|  for ( p = (char*)m->arr.first; p < (char*)m->arr.last;
1176|       p += elem_size ) {
1177|
1178|    if ( Offset_ref( ofsFlag, p, bool ) )
1179|      n++;
1180|  }
1181|
1182|  return  n;
1183|}
1184|#endif
1185|
1186| 
1187|/***********************************************************************
1188|  6-3. <<< [ArrX_Able_getFirst_imp] 最初の有効な要素を返す >>> 
1189|************************************************************************/
1190|#ifdef  USES_OFFSET
1191|void*  ArrX_Able_getFirst_imp( ArrX_Able* m, int elem_size, Offset ofsFlag )
1192|{
1193|  char*  p;
1194|  ERRORS_INITCHK( m, 1 );
1195|
1196|  for ( p = (char*)m->arr.first; p < (char*)m->arr.last;
1197|       p += elem_size ) {
1198|
1199|    if ( Offset_ref( ofsFlag, p, bool ) )
1200|      return  (void*)p;
1201|  }
1202|  return  NULL;
1203|}
1204|#endif
1205|
1206| 
1207|/***********************************************************************
1208|  6-4. <<< [ArrX_Able_getFirstDis_imp] 最初の無効な要素を返す >>> 
1209|************************************************************************/
1210|#ifdef  USES_OFFSET
1211|void*  ArrX_Able_getFirstDis_imp( ArrX_Able* m, int elem_size, Offset ofsFlag )
1212|{
1213|  char*  p;
1214|  ERRORS_INITCHK( m, 1 );
1215|
1216|  for ( p = (char*)m->arr.first; p < (char*)m->arr.last;
1217|       p += elem_size ) {
1218|
1219|    if ( ! Offset_ref( ofsFlag, p, bool ) )
1220|      return  (void*)p;
1221|  }
1222|  error2_0( ArrX_Err_Full, "ArrX_Able が満杯です" );
1223|  return  NULL;  /* dummy */
1224|}
1225|#endif
1226|
1227| 
1228|/***********************************************************************
1229|  6-5. <<< [ArrX_Able_forEach_imp] ArrX_Able_forEach用カウントアップ >>> 
1230|【引数】
1231|  ・void*  pp;       カウントアップするポインタのアドレス
1232|  ・int  size;       配列要素サイズ
1233|  ・Offset  offset;  配列要素の ArrX_Able_flag メンバ変数へのオフセット
1234|  ・void*  over;     カウント・オーバーする配列要素のアドレス
1235|【補足】
1236|・内部用です。
1237|************************************************************************/
1238|#ifdef  USES_OFFSET
1239|void  ArrX_Able_forEach_imp( void* pp, int size, Offset offset, void* over )
1240|{
1241|  char**  p = (char**)pp;
1242|
1243|  while ( ! Offset_ref( offset, *p, bool ) && *p < (char*)over ) {
1244|    *p += size;
1245|  }
1246|}
1247|#endif
1248|
1249|
1250| 
1251|/***********************************************************************
1252|  6-6. <<< [ArrX_Able_forEachDisabled_imp] ArrX_Able_forEachDisabled用カウントアップ >>> 
1253|【引数】
1254|  ・void*  pp;       カウントアップするポインタのアドレス
1255|  ・int  size;       配列要素サイズ
1256|  ・Offset  offset;  配列要素の ArrX_Able_flag メンバ変数へのオフセット
1257|  ・void*  over;     カウント・オーバーする配列要素のアドレス
1258|【補足】
1259|・内部用です。
1260|************************************************************************/
1261|#ifdef  USES_OFFSET
1262|void  ArrX_Able_forEachDisabled_imp( void* pp, int size, Offset offset, void* over )
1263|{
1264|  char**  p = (char**)pp;
1265|
1266|  while ( Offset_ref( offset, *p, bool ) && *p < (char*)over ) {
1267|    *p += size;
1268|  }
1269|}
1270|#endif
1271|
1272|
1273| 
1274|/**************************************************************************
1275|  6-7. <<< [ArrX_Able_search_s_imp] 文字列型のキーを用いて線形検索する >>> 
1276|***************************************************************************/
1277|#ifdef  USES_OFFSET
1278|void* ArrX_Able_search_s_imp( ArrX_Able* m, Offset_Key* key, const char* val,
1279|  int elem_sizeof, Offset elem_ofs )
1280|{
1281|  void*  ret;
1282|  ERRORS_INITCHK( m, 1 );
1283|  ASSERT( Offset_Key_chk( key ) );
1284|
1285|  for (;;) {
1286|    ret = ArrX_search_s_imp( &m->arr, key, val, elem_sizeof );
1287|
1288|    /* 有効な要素を返す */
1289|    if ( ret == NULL )  return  NULL;
1290|    if ( Offset_ref( elem_ofs, ret, ArrX_AbleElem ) )  return  ret;
1291|
1292|    ret = (char*)ret + elem_sizeof;
1293|  }
1294|}
1295|#endif
1296|
1297| 
1298|/*-------------------------------------------------------------------------*/
1299|/* ◆7. <<<< ソート・バッファ (ArrX_Sort) >>>> */ 
1300|/*-------------------------------------------------------------------------*/
1301|
1302|
1303| 
1304|#ifdef  USES_OFFSET 
1305| 
1306|/**************************************************************************
1307|  7-1. <<< [ArrX_Sort_init] 初期化する >>> 
1308|【引数】
1309|  ・void**  mem;          ソート・バッファ(ソート用ワーク領域)
1310|  ・int  mem_sizeof;   mem のメモリサイズ
1311|  ・Offset_Key*  key;       ソート・キー
1312|【補足】
1313|・mem には、void* 型の配列の先頭アドレスを渡します。要素数は、ソートする
1314|  要素の数と等しいかそれ以上にします。
1315|・初期化すると、ソート・バッファは空になります。
1316|***************************************************************************/
1317|#ifdef  USES_OFFSET
1318|void  ArrX_Sort_init( ArrX_Sort* m, void** mem, int mem_sizeof,
1319|  Offset_Key* key )
1320|{
1321|  ERRORS_INITCHK( m, 0 );
1322|
1323|  ASSERT( Offset_Key_chk( key ) );
1324|
1325|  m->first = mem;
1326|  m->last = mem;
1327|  m->bufLast = (void**)((char*)mem + mem_sizeof);
1328|  m->key = key;
1329|
1330|  ASSERT( ArrX_Sort_chk( m ) );
1331|}
1332|#endif
1333|
1334| 
1335|/**************************************************************************
1336|  7-2. <<< [ArrX_Sort_chk] 正規チェック >>> 
1337|【補足】
1338|・ツリー自体の正規チェックはしていません。
1339|***************************************************************************/
1340|#ifdef USES_OFFSET
1341|int  ArrX_Sort_chk( ArrX_Sort* m )
1342|{
1343|  ERRORS_INITCHK_FOR_SUB( m, 1 );
1344|
1345|  return  m->first <= m->last &&
1346|          m->first < m->bufLast &&
1347|          m->last <= m->bufLast &&
1348|          Offset_Key_chk( m->key );
1349|}
1350|#endif
1351|
1352| 
1353|/**************************************************************************
1354|  7-3. <<< [ArrX_Sort_print] デバッグ表示 >>> 
1355|【補足】
1356|・プライオリティ・キューの要素については、データの先頭アドレスとキーの値のみ
1357|  表示します。
1358|***************************************************************************/
1359|#ifndef  ERRORS_CUT_DEBUG_TOOL
1360|#ifdef USES_OFFSET
1361|void  ArrX_Sort_print( ArrX_Sort* m, const char* title )
1362|{
1363|  int  width = 1;
1364|  int  x = 1, y = 1;
1365|  void**  p;
1366|
1367|  Errors_printf( "%sArrX_Sort(%p) nElem=%d, mElem=%d, buf=(%p..%p)",
1368|    title, m, m->last - m->first, m->bufLast - m->first,
1369|    m->first, m->bufLast );
1370|  Offset_Key_print( m->key, title );
1371|
1372|  Errors_printf( "%s(1)", title );
1373|  for ( p = m->first; p < m->last; p++ ) {
1374|    Offset_Key_printData( m->key, *p, title );
1375|
1376|    /* ツリーの次の段になったら1行空ける */
1377|    x++;
1378|    if ( x > width && p < m->last - 1 ) {
1379|      x = 1;  y++;  width *= 2;
1380|      Errors_printf( "%s(%d)", title, y );
1381|    }
1382|  }
1383|}
1384|#endif
1385|#endif
1386|
1387|
1388| 
1389|/**************************************************************************
1390|  7-4. <<< [ArrX_Sort_pushPQ] プライオリティ・キューとしてバッファに追加する >>> 
1391|【引数】
1392|  ・void* plus;  追加するデータへのポインタ
1393|【補足】
1394|・プライオリティ・キューは、配列にすべての要素をプッシュすると、ソートされ
1395|  た順番にポップされていきます。
1396|・配列にはデータへのポインタのみ格納されるので、データの有効期限に注意して
1397|  ください。
1398|・オーダーは log(N) N:要素数 と高速です。
1399|
1400|【内部補足】
1401|・配列を、親ノード番号が、(i-1)/2、子ノード番号が、i*2+1、i*2+2 になるような
1402|  ツリー構造とみなしています。
1403|  
1404|
1405|・プッシュすると、すべてのノードのキー値を子ノードのキー値より優先順位が高い
1406|  (昇順の場合は値が小さい方、降順の場合は値が大きい方)という部分的なソート
1407|  状態になります。ポップすると最も優先順位の高いものが取り出されます。
1408|  つまり、すべての要素をプッシュ(ArrX_Sort_pushPQ)した後、ポップ(
1409|  ArrX_Sort_popPQ)していくと、ソートされたデータを最初から取り出すことが
1410|  出来るということです。
1411|【参考】
1412|・C++ STL のプライオリティキューによるハフマンツリーの実装
1413|  - Mark R.Nelson - DDJ Japan May.1996 p30
1414|***************************************************************************/
1415|#ifdef USES_OFFSET
1416|void  ArrX_Sort_pushPQ( ArrX_Sort* m, void* plus )
1417|{
1418|  int  i, iParent;   /* 処理中の配列番号と、その親ノード(ルート方向) */
1419|  void **p, **pParent; /* 処理中の要素のアドレスと、その親ノード */
1420|  void* sp;
1421|
1422|  ASSERT( ArrX_Sort_chk( m ) );
1423|
1424|  /* 配列が満杯なら、追加しない */
1425|  if ( m->last == m->bufLast ) {
1426|    #ifdef _CHECKER
1427|      error();
1428|    #endif
1429|    return;
1430|  }
1431|
1432|  /* 要素を配列の最後に追加 */
1433|  *m->last = plus;
1434|  m->last ++;
1435|
1436|  /*「正規化」すべてのノードを、子ノードより優先順位を高くする */
1437|  i = m->last - m->first - 1;
1438|  p = m->last - 1;
1439|  while ( i > 0 ) {
1440|    iParent = (i-1) / 2;
1441|    pParent = m->first + iParent;
1442|
1443|    /* あるノードを親ノードより優先順位を低くする */
1444|    if ( Offset_Key_cmp( m->key, *p, *pParent ) > 0 ) {
1445|
1446|      /* 親ノードと入れ替える */
1447|      sp = *p;  *p = *pParent;  *pParent = sp;
1448|      i = iParent;  p = pParent;
1449|    }
1450|    else {
1451|      /* 正規化された */
1452|      break;
1453|    }
1454|  }
1455|
1456|  ASSERT( ArrX_Sort_chk( m ) );
1457|}
1458|#endif
1459|
1460| 
1461|/**************************************************************************
1462|  7-5. <<< [ArrX_Sort_popPQ] プライオリティ・キューとしてバッファから取り出す >>> 
1463|【引数】
1464|  ・void*  返り値;   最も優先順位の高い要素のアドレス
1465|【補足】
1466|・返り値として返されたポインタは、配列から取り除かれます。
1467|・キューが空の場合は、エラーになるので、ArrX_Sort_isEmpty 関数で調べて
1468|  からこの関数を呼び出してください。
1469|***************************************************************************/
1470|#ifdef USES_OFFSET
1471|void*  ArrX_Sort_popPQ( ArrX_Sort* m )
1472|{
1473|  int  i, iChild;   /* 処理中の配列番号と、その子ノードの配列番号の小さい方 */
1474|  void **p, **pChild; /* 要素番号 i の要素のアドレスと、同 iChild */
1475|  int  iLast;       /* 最後の配列番号 */
1476|  void*  ret;
1477|  void*  sp;
1478|
1479|  ASSERT( ArrX_Sort_chk( m ) );
1480|
1481|  /* 空の場合 NULL を返す */
1482|  ASSERT( m->first != m->last );
1483|
1484|  /* 優先順位のいちばん高いノードを ret に格納し、配列から取り除く */
1485|  ret = *m->first;
1486|  m->last --;
1487|  *m->first = *m->last;
1488|  iLast = m->last - m->first - 1;
1489|
1490|  /*「正規化」すべてのノードを、子ノードより優先順位を高くする */
1491|  i = 0;  iChild = 1;
1492|  p = m->first;  pChild = p + 1;
1493|  while ( iChild < iLast ) {
1494|
1495|    /* 2つの子ノードのうち優先順位の高いものを iChild にする */
1496|    if ( Offset_Key_cmp( m->key, *(pChild + 1), *pChild ) > 0 ) {
1497|      iChild++;  pChild++;
1498|    }
1499|
1500|    /* あるノードを子ノードより優先順位を高くする */
1501|    if ( Offset_Key_cmp( m->key, *p, *pChild ) < 0 ) {
1502|
1503|      /* 子ノードと入れ替える */
1504|      sp = *p;  *p = *pChild;  *pChild = sp;
1505|      i = iChild;  p = pChild;
1506|      iChild = i * 2 + 1;  pChild = m->first + iChild;
1507|    }
1508|    else {
1509|      /* 正規化された */
1510|      ASSERT( ArrX_Sort_chk( m ) );
1511|      return ret;
1512|    }
1513|  }
1514|  if ( iChild == iLast ) {  /* 子ノードが片方しか無い場合 */
1515|    if ( Offset_Key_cmp( m->key, *p, *pChild ) < 0 ) {
1516|      /* 子ノードと入れ替える */
1517|      sp = *p;  *p = *pChild;  *pChild = sp;
1518|    }
1519|  }
1520|  ASSERT( ArrX_Sort_chk( m ) );
1521|  return  ret;
1522|}
1523|#endif
1524| 
1525|#endif  /* USES_OFFSET */ 
1526| 
1527|/*-------------------------------------------------------------------------*/
1528|/* ◆8. <<<< ハッシュテーブルを用いた辞書 (ArrX_Dic) >>>> */ 
1529|/*-------------------------------------------------------------------------*/
1530| 
1531|#if defined(USES_OFFSET) && defined(USES_STRX) 
1532| 
1533|/**************************************************************************
1534|  8-1. <<< [ArrX_Dic_init] 初期化する >>> 
1535|【引数】
1536|  ・int        width;          ハッシュテーブルの幅
1537|  ・ArrX_Buf*  subDics;        ArrX_Buf 型の配列の先頭アドレス
1538|  ・int     subDics_sizeof; subDics のメモリサイズ
1539|  ・Offset_Key*  key;            キー、(ワードの位置)
1540|  ・void*      elems;          配列(辞書要素)の先頭アドレス
1541|  ・int     elems_sizeof;   配列(辞書要素)のメモリサイズ
1542|***************************************************************************/
1543|void  ArrX_Dic_init( ArrX_Dic* m,
1544|  int width, ArrX_Buf* subDics, int subDics_sizeof,
1545|  Offset_Key* key, void* elems, int elems_sizeof )
1546|{
1547|  int  i;
1548|  void*  pElem;
1549|  int  elem_sizeof = elems_sizeof / width;
1550|
1551|  ASSERT( subDics_sizeof / sizeof(ArrX_Buf) == (unsigned int)width );
1552|  ASSERT( elems_sizeof >= width );
1553|
1554|  /* subDics を初期化する */
1555|  m->subDics = subDics;
1556|  pElem = elems;
1557|  for ( i = 0; i < width; i++ ) {
1558|    ArrX_Buf_init( &m->subDics[i], pElem, elem_sizeof );
1559|    pElem = (char*)pElem + elem_sizeof;
1560|  }
1561|
1562|  /* その他の属性を初期化する */
1563|  m->width = width;
1564|  m->key = key;
1565|}
1566|
1567| 
1568|/**************************************************************************
1569|  8-2. <<< [ArrX_Dic_search_imp] 検索する >>> 
1570|【引数】
1571|  ・char*  word;          ワード
1572|  ・int elem_sizeof;   検索する要素のサイズ
1573|  ・void*  返り値;        検索された領域のアドレス、または NULL
1574|【補足】
1575|・指定したワードが辞書に登録されていない場合、NULL を返します。
1576|・この関数は、ArrX_Dic_search マクロの実装部です。
1577|***************************************************************************/
1578|void*  ArrX_Dic_search_imp( ArrX_Dic* m, const char* word,
1579|  int elem_sizeof )
1580|{
1581|  int  hash = StrX_getHash( word, m->width );
1582|
1583|  return  ArrX_Buf_search_s_imp( &m->subDics[hash], m->subDics[hash].first,
1584|     m->key, word, elem_sizeof );
1585|}
1586|
1587| 
1588|/**************************************************************************
1589|  8-3. <<< [ArrX_Dic_searchNext_imp] ArrX_Dic_searchNext マクロの実装部 >>> 
1590|***************************************************************************/
1591|void*  ArrX_Dic_searchNext_imp( ArrX_Dic* m, const void* prev,
1592|  int elem_sizeof )
1593|{
1594|  char*  word = Offset_Key_getCharPtr( m->key, (void*)prev );
1595|  int  hash = StrX_getHash( word, m->width );
1596|
1597|  ASSERT( word != NULL );
1598|
1599|  return  ArrX_Buf_search_s_imp( &m->subDics[hash], (char*)prev + elem_sizeof,
1600|     m->key, word, elem_sizeof );
1601|}
1602|
1603| 
1604|/**************************************************************************
1605|  8-4. <<< [ArrX_Dic_alloc_imp] ArrX_Dic_alloc マクロの実装部 >>> 
1606|***************************************************************************/
1607|void*  ArrX_Dic_alloc_imp( ArrX_Dic* m, const char* word,
1608|  int alloc_sizeof )
1609|{
1610|  int  hash = StrX_getHash( word, m->width );
1611|
1612|  if ( ArrX_Buf_search_s_imp( &m->subDics[hash], m->subDics[hash].first,
1613|       m->key, word, alloc_sizeof ) == NULL ) {
1614|    return  ArrX_Buf_alloc_imp( &m->subDics[hash], alloc_sizeof );
1615|  }
1616|  else
1617|    return  NULL;  /* すでに登録されている */
1618|}
1619|
1620| 
1621|/**************************************************************************
1622|  8-5. <<< [ArrX_Dic_allocDup_imp] ArrX_Dic_allocDup マクロの実装部 >>> 
1623|***************************************************************************/
1624|void*  ArrX_Dic_allocDup_imp( ArrX_Dic* m, const char* word,
1625|  int alloc_sizeof )
1626|{
1627|  int  hash = StrX_getHash( word, m->width );
1628|
1629|  return  ArrX_Buf_alloc_imp( &m->subDics[hash], alloc_sizeof );
1630|}
1631|
1632| 
1633|/***********************************************************************
1634|  8-6. <<< [ArrX_Dic_allocFromFile] ファイルから登録する >>> 
1635|【引数】
1636|  ・ArrX_Dic*  m;  辞書
1637|  ・char*  path;      登録する文字列が書かれたファイル
1638|  ・StrX_Mem*  mem;   文字列記憶領域
1639|【補足】
1640|・文字列型(char*型)の配列をハッシュテーブルに登録します。
1641|・ファイルのフォーマットは、文字列をスペース系文字(' ','\t','\n')で
1642|  区切るものです。(fscanf と同様)
1643|・テーブルの要素は、構造体ではなく char* 型の固定です。
1644|  ですから、キーワードが存在するかどうかの判定しか用途がありません。
1645|・word_size - 1 文字より大きい文字列は、それ以降を切り捨てて登録します。
1646|************************************************************************/
1647|#if  defined(USES_FILEX)
1648|#ifndef  FOR_WINCE
1649|void  ArrX_Dic_allocFromFile( ArrX_Dic* m,
1650|  const char* path, StrX_Mem* mem )
1651|{
1652|  enum { word_size = 256 };
1653|  char  word[256];
1654|  FILE*  file;
1655|  char**  data;
1656|
1657|  file = FileX_open( path, "rt" );
1658|
1659|  for (;;)  {
1660|    fscanf( file, "%s", word );
1661|    if ( feof( file ) )  break;
1662|    data = ArrX_Dic_alloc( m, word, char* );
1663|    if ( data != NULL ) {
1664|      *data = StrX_Mem_alloc( mem );
1665|      strcpy( *data, word );
1666|    }
1667|  }
1668|  fclose( file );
1669|}
1670|#endif
1671|#endif
1672|
1673|
1674| 
1675|/***********************************************************************
1676|  8-7. <<< [ArrX_Dic_print] デバッグ表示する >>> 
1677|【引数】
1678|  ・int  elem_size;  辞書要素のメモリサイズ
1679|  ・print;           辞書要素のデバッグ表示をする関数
1680|【補足】
1681|・print は、第1引数が要素へのポインタ、第2引数が title です。
1682|************************************************************************/
1683|#ifndef  ERRORS_CUT_DEBUG_TOOL
1684|void  ArrX_Dic_print( ArrX_Dic* m, const char* title, int elem_size,
1685|  void (*elem_print)(void*,const char*) )
1686|{
1687|  ArrX_Buf*  buf;
1688|  ArrX_Buf*  buf_over;
1689|  void*      pElem;
1690|
1691|  Errors_printf( "%sArrX_Dic[%p] width=%d", title, m, m->width );
1692|  Offset_Key_print( m->key, title );
1693|
1694|  /* 配列要素をデバッグ表示する */
1695|  for ( buf = m->subDics, buf_over = m->subDics + m->width;
1696|        buf < buf_over;  buf++ ) {
1697|    Errors_printf( "%s [%d] = %d", title, buf - m->subDics,
1698|      ArrX_Buf_getN_imp( buf, elem_size ) );
1699|  }
1700|
1701|  /* 配列要素をデバッグ表示する */
1702|  for ( buf = m->subDics, buf_over = m->subDics + m->width;
1703|        buf < buf_over;  buf++ ) {
1704|    Errors_printf( "%s[%d] = %d ------------------------------",
1705|      title, buf - m->subDics,
1706|      ArrX_Buf_getN_imp( buf, elem_size ) );
1707|    for ( ArrX_Buf_forEach_imp( buf, &pElem, elem_size ) ) {
1708|      (*elem_print)( pElem, title );
1709|    }
1710|  }
1711|}
1712|#endif
1713| 
1714|/***********************************************************************
1715|  8-8. <<< [ArrX_Dic_forEachDup_imp] ArrX_Dic_forEachDup の実装部 >>> 
1716|************************************************************************/
1717|void*  ArrX_Dic_forEach_Dup_next( ArrX_Dic* m, ArrX_DicDupIter* dup,
1718|  int elem_size, void* key_elem );
1719|
1720|
1721|bool  ArrX_Dic_forEachDup_imp( ArrX_Dic* m, ArrX_DicDupIter* dup, int elem_size )
1722|{
1723|  void*  key_elem;  /* 重複候補の辞書要素 */
1724|  char*  kword;
1725|  void*  dup_elem;
1726|
1727|  /* 重複キーの候補を key_elem に設定する */
1728|  if ( dup->first == NULL ) {
1729|    dup->dic = m;
1730|    dup->pSubDic = m->subDics;
1731|    key_elem = ArrX_Dic_forEach_Dup_next( m, dup, elem_size,
1732|      dup->pSubDic->first );
1733|    if ( key_elem == NULL )  return  false;
1734|  }
1735|  else {
1736|    key_elem = ArrX_Dic_forEach_Dup_next( m, dup, elem_size,
1737|      (void*)( (char*)dup->first + elem_size ) );
1738|    if ( key_elem == NULL )  return  false;
1739|  }
1740|
1741|  /* 候補 key_elem のキーに一致する要素を検索する */
1742|  for (;;) {
1743|
1744|    /* dup->pSubDic の中から、キーが候補と一致する要素を検索する */
1745|    kword = Offset_Key_getCharPtr( m->key, key_elem );
1746|    ASSERT( kword != NULL );
1747|
1748|    dup_elem = ArrX_Buf_search_s_imp( dup->pSubDic,
1749|      (char*)key_elem + elem_size,  /* 候補の次の要素から検索する */
1750|      m->key, kword, elem_size );
1751|
1752|    /* 見つかったら、それを採用する */
1753|    if ( dup_elem != NULL ) {
1754|      dup->first = key_elem;
1755|      dup->p = NULL;
1756|
1757|      return  true;
1758|    }
1759|
1760|    /* 見つからなかったら、次の候補を key_elem に設定する */
1761|    key_elem = ArrX_Dic_forEach_Dup_next( m, dup, elem_size,
1762|      (void*)( (char*)key_elem + elem_size ) );
1763|    if ( key_elem == NULL )  return  false;
1764|  }
1765|}
1766|
1767|
1768|
1769|/***********************************************************************
1770|  8-9. <<< [ArrX_Dic_forEach_Dup_next] 以前候補になっていない次の重複要素の候補を返す >>>
1771|【引数】
1772|  ・void*  key_elem;  以前候補になったか分らかない次の重複要素の候補
1773|  ・void*  返り値;    以前候補になっていない次の重複要素の候補(NULL=次はない)
1774|************************************************************************/
1775|void*  ArrX_Dic_forEach_Dup_next( ArrX_Dic* m, ArrX_DicDupIter* dup,
1776|  int elem_size, void* key_elem )
1777|{
1778|  char*  kword;
1779|  void*  dup_elem;
1780|
1781|  for (;;) {
1782|
1783|    if ( key_elem >= dup->pSubDic->last ) {
1784|      do {
1785|        dup->pSubDic ++;
1786|        if ( dup->pSubDic >= m->subDics + m->width )  return  NULL;
1787|        key_elem = dup->pSubDic->first;
1788|      } while ( key_elem >= dup->pSubDic->last );
1789|
1790|      return  key_elem;
1791|    }
1792|
1793|    if ( dup->first == NULL ||
1794|         strcmp( Offset_Key_getCharPtr( m->key, key_elem ),
1795|                 Offset_Key_getCharPtr( m->key, dup->first ) ) != 0 ) {
1796|
1797|      /* すでに候補に挙がったものでなければ採用する */
1798|      kword = Offset_Key_getCharPtr( m->key, key_elem );
1799|      ASSERT( kword != NULL );
1800|      for ( dup_elem = dup->pSubDic->first;
1801|            dup_elem < key_elem;
1802|            dup_elem = (void*)( (char*)dup_elem + elem_size ) ) {
1803|        if ( strcmp( Offset_Key_getCharPtr( m->key, dup_elem ), kword ) == 0 )
1804|          break;
1805|      }
1806|      if ( dup_elem == key_elem )
1807|        return  key_elem;
1808|    }
1809|    key_elem = (void*)( (char*)key_elem + elem_size );
1810|  }
1811|}
1812| 
1813|/***********************************************************************
1814|  8-10. <<< [ArrX_DicDupIter_forEach_imp] ArrX_DicDupIter_forEach の実装部 >>> 
1815|************************************************************************/
1816|bool  ArrX_DicDupIter_forEach_imp( ArrX_DicDupIter* dup, int elem_size )
1817|{
1818|  char*  kword;
1819|  void*  elem;
1820|
1821|  if ( dup->p == NULL )
1822|    { dup->p = dup->first;  return  true; }
1823|  else
1824|    elem = dup->p;
1825|
1826|  kword = Offset_Key_getCharPtr( dup->dic->key, dup->first );
1827|  ASSERT( kword != NULL );
1828|
1829|  elem = ArrX_Buf_search_s_imp( dup->pSubDic, (char*) elem + elem_size,
1830|    dup->dic->key, kword, elem_size );
1831|  dup->p = elem;
1832|
1833|  return  ( elem != NULL );
1834|}
1835|
1836| 
1837|#endif  /* USES_OFFSET */ 
1838| 
1839|/*-------------------------------------------------------------------------*/
1840|/* ◆9. <<<< ハッシュテーブルを用いた辞書の走査子 (ArrX_DicIter) >>>> */ 
1841|/*-------------------------------------------------------------------------*/
1842|
1843|
1844| 
1845|/**************************************************************************
1846|  9-1. <<< [ArrX_DicIter_init_imp] 走査子を初期化する >>> 
1847|【補足】
1848|・この関数は、ArrX_DicIter_init マクロの実装です。
1849|***************************************************************************/
1850|#ifdef USES_STRX
1851|void  ArrX_DicIter_init_imp( ArrX_DicIter* m, ArrX_Dic* dic, int size )
1852|{
1853|  m->dic = dic;
1854|  m->curBuf = dic->subDics;
1855|  m->curData = (void*)((char*)m->curBuf->first - size);
1856|  m->iBuf = 0;
1857|  m->size = size;
1858|}
1859|
1860|#endif /* USES_STRX */
1861|
1862|
1863| 
1864|/**************************************************************************
1865|  9-2. <<< [ArrX_DicIter_next_imp] 走査子を次の辞書要素に移動する >>> 
1866|【引数】
1867|  ・int  size;   辞書要素のサイズ
1868|  ・int  返り値;    0=正常、1=次の辞書要素は無い
1869|***************************************************************************/
1870|#ifdef USES_STRX
1871|int   ArrX_DicIter_next( ArrX_DicIter* m )
1872|{
1873|  /* 現在のバッファ curBuf に次の辞書要素が有れば、それを指す */
1874|  m->curData = (void*)((char*)m->curData + m->size);
1875|  if ( m->curData < m->curBuf->last ) {
1876|    return  0;
1877|  }
1878|
1879|  /* 次の辞書要素が無ければ、辞書要素を持っている次のバッファを指す */
1880|  else {
1881|    do {
1882|      m->curBuf ++;
1883|      m->iBuf ++;
1884|      if ( m->iBuf == m->dic->width )  return  1;
1885|    } while ( m->curBuf->first == m->curBuf->last );
1886|    m->curData = m->curBuf->first;
1887|    return  0;
1888|  }
1889|}
1890|
1891|#endif /* USES_STRX */
1892|
1893|
1894| 
1895|/*---------------------------------------------------------------------*/
1896|/* ◆10. <<<< はしごポインタ (ArrX_ArrsPtrI) >>>> */ 
1897|/*---------------------------------------------------------------------*/
1898| 
1899|/***********************************************************************
1900|  10-1. <<< [ArrX_ArrsPtrI_init] 初期化する >>> 
1901|【引数】
1902|  ・int*  arr[];  それぞれの配列のアドレスの配列
1903|  ・int  arr_n[];  それぞれの配列の要素数の配列
1904|  ・int  nArr;  arr の要素数
1905|  ・int  iArr;  ポインタの初期値(1)(arr の配列番号)
1906|  ・int  p;  ポインタの初期値(2)(arr[iArr] の先頭を0としたアドレス)
1907|************************************************************************/
1908|void  ArrX_ArrsPtrI_init( ArrX_ArrsPtrI* m, int* arr[], int  arr_n[], int nArr,
1909|  int iArr, int p )
1910|{
1911|  m->arr = arr;  m->arr_n = arr_n;  m->nArr = nArr;
1912|  ArrX_ArrsPtrI_set( m, iArr, p );
1913|}
1914|
1915|
1916| 
1917|/***********************************************************************
1918|  10-2. <<< [ArrX_ArrsPtrI_set] ポインタの値を設定する(ランダム指定)>>> 
1919|【引数】
1920|  ・int  iArr;  配列の番号(要素番号ではない)
1921|  ・int  p;     配列番号(iArr の先頭を基準とする)
1922|************************************************************************/
1923|void  ArrX_ArrsPtrI_set( ArrX_ArrsPtrI* m, int iArr, int p )
1924|{
1925|  m->p = m->arr[iArr];
1926|  m->iArr = iArr;
1927|  m->pOver = m->arr[iArr] + m->arr_n[iArr];
1928|
1929|  ArrX_ArrsPtrI_plus( m, p );
1930|}
1931|
1932|
1933| 
1934|/***********************************************************************
1935|  10-3. <<< [ArrX_ArrsPtrI_plus] ポインタの演算をする >>> 
1936|【引数】
1937|  ・int  p;     配列番号の増分(正の数のみ)
1938|************************************************************************/
1939|void  ArrX_ArrsPtrI_plus( ArrX_ArrsPtrI* m, unsigned int plus )
1940|{
1941|  m->p += plus;
1942|
1943|  while ( m->p >= m->pOver ) {
1944|    m->iArr ++;
1945|    m->p = m->arr[m->iArr] + ( m->p - m->pOver );
1946|    m->pOver = m->arr[m->iArr] + m->arr_n[m->iArr];
1947|  }
1948|}
1949|
1950|
1951| 
1952|/*-------------------------------------------------------------------------*/
1953|/* ◆11. <<<< 実装 (ArrX_Imp) >>>> */ 
1954|/*-------------------------------------------------------------------------*/
1955|
1956|
1957| 
1958|/**************************************************************************
1959|  11-1. <<< [ArrX_Imp_linearSearch] 線形検索する(1) >>> 
1960|【引数】
1961|  ・void*  start;     配列の先頭アドレス
1962|  ・void*  last;      配列の末尾の次のアドレス
1963|  ・int  elem_size;   要素のサイズ
1964|  ・void*  key;       キーのアドレス
1965|  ・int  key_offset;  要素中のキーオフセット
1966|  ・int  key_type;    キーのタイプ(補足を参照)
1967|  ・int  key_size;    キーのサイズ(補足を参照)
1968|  ・int  返り値;      見つかった要素のアドレス、または NULL=見つからない
1969|【補足】
1970|・key_type は、0=バイナリ か 1=ポインタのどちらかを指定します。
1971|・key_size を -1 にすると、'\0'付き文字列として比較します。
1972|・1つ見つかった後で、もう1つ見つけようとする場合、start に前に見つかった
1973|  要素の次の要素のアドレスを指定します。例:(type*)p + 1
1974|***************************************************************************/
1975|void*  ArrX_Imp_linearSearch( void* start, void* last, int elem_size,
1976|  const void* key, int key_offset, int key_type, int key_size )
1977|{
1978|  int  flag;        /* 比較結果, memcmp 関数と同じ返り値 */
1979|  void*  elem_key;  /* 要素中のキーのアドレス */
1980|
1981|  if ( key_type == 0 ) {
1982|    if ( key_size >= 0 ) {
1983|      while ( start < last ) {
1984|        elem_key = ((char*)start + key_offset);
1985|        flag = memcmp( elem_key, key, key_size );
1986|        if ( flag == 0 )  return  start;
1987|        start = (char*)start + elem_size;
1988|      }
1989|    }
1990|    else {
1991|      while ( start < last ) {
1992|        elem_key = ((char*)start + key_offset);
1993|        flag = strcmp( (char*)elem_key, (char*)key );
1994|        if ( flag == 0 )  return  start;
1995|        start = (char*)start + elem_size;
1996|      }
1997|    }
1998|  }
1999|  else {
2000|    if ( key_size >= 0 ) {
2001|      while ( start < last ) {
2002|        elem_key = *((void**)((char*)start + key_offset));
2003|        flag = memcmp( elem_key, key, key_size );
2004|        if ( flag == 0 )  return  start;
2005|        start = (char*)start + elem_size;
2006|      }
2007|    }
2008|    else {
2009|      while ( start < last ) {
2010|        elem_key = *((void**)((char*)start + key_offset));
2011|        flag = strcmp( (char*)elem_key, (char*)key );
2012|        if ( flag == 0 )  return  start;
2013|        start = (char*)start + elem_size;
2014|      }
2015|    }
2016|  }
2017|
2018|  return  NULL;
2019|}
2020|
2021|
2022| 
2023|/**************************************************************************
2024|  11-2. <<< [ArrX_Imp_linearSearchF] 線形検索する(2) >>> 
2025|【引数】
2026|  ・void*  start;     配列の先頭アドレス
2027|  ・void*  last;      配列の末尾の次のアドレス
2028|  ・int  elem_size;   要素のサイズ
2029|  ・void*  key;       キーのアドレス
2030|  ・int  key_offset;  要素中のキーオフセット
2031|  ・void*  param;     判定関数に渡す任意のパラメータのアドレス
2032|  ・ArrX_CmpF  func;  判定関数のアドレス
2033|  ・int  返り値;      見つかった要素のアドレス、または NULL=見つからない
2034|【補足】
2035|・1つ見つかった後で、もう1つ見つけようとする場合、start に前に見つかった
2036|  要素の次の要素のアドレスを指定します。例:(type*)p + 1
2037|***************************************************************************/
2038|void*  ArrX_Imp_linearSearchF( void* start, void* last, int elem_size,
2039|  const void* key, int key_offset, void* param, ArrX_CmpF func )
2040|{
2041|  int  flag;        /* 比較結果, memcmp 関数と同じ返り値 */
2042|  void*  elem_key;  /* 要素中のキーのアドレス */
2043|
2044|  while ( start < last ) {
2045|    elem_key = ((char*)start + key_offset);
2046|    flag = (*func)( elem_key, (void*)key, param );
2047|    if ( flag == 0 )  return  start;
2048|    start = (char*)start + elem_size;
2049|  }
2050|  return  NULL;
2051|}
2052|
2053|
2054| 
2055|/**************************************************************************
2056|  11-3. <<< [ArrX_Imp_linearSearchP] ポインタ配列を線形検索する(1) >>> 
2057|【引数】
2058|  ・void**  start;    ポインタ配列の先頭アドレス
2059|  ・void**  last;     ポインタ配列の末尾の次のアドレス
2060|  ・void*  key;       キーのアドレス
2061|  ・int  key_offset;  要素中のキーオフセット
2062|  ・int  key_type;    キーのタイプ(補足を参照)
2063|  ・int  key_size;    キーのサイズ(補足を参照)
2064|  ・int  返り値;      見つかった要素のアドレス、または NULL=見つからない
2065|【補足】
2066|・key_type は、0=バイナリ か 1=ポインタのどちらかを指定します。
2067|・key_size を -1 にすると、'\0'付き文字列として比較します。
2068|・1つ見つかった後で、もう1つ見つけようとする場合、start に前に見つかった
2069|  要素の次の要素のアドレスを指定します。例:(type*)p + 1
2070|***************************************************************************/
2071|void*  ArrX_Imp_linearSearchP( void** start, void** last,
2072|  const void* key, int key_offset, int key_type, int key_size )
2073|{
2074|  int  flag;        /* 比較結果, memcmp 関数と同じ返り値 */
2075|  void*  elem_key;  /* 要素中のキーのアドレス */
2076|
2077|  if ( key_type == 0 ) {
2078|    if ( key_size >= 0 ) {
2079|      while ( start < last ) {
2080|        elem_key = ((char*)*start + key_offset);
2081|        flag = memcmp( elem_key, key, key_size );
2082|        if ( flag == 0 )  return  start;
2083|        start ++;
2084|      }
2085|    }
2086|    else {
2087|      while ( start < last ) {
2088|        elem_key = ((char*)*start + key_offset);
2089|        flag = strcmp( (char*)elem_key, (char*)key );
2090|        if ( flag == 0 )  return  start;
2091|        start ++;
2092|      }
2093|    }
2094|  }
2095|  else {
2096|    if ( key_size >= 0 ) {
2097|      while ( start < last ) {
2098|        elem_key = *((void**)((char*)*start + key_offset));
2099|        flag = memcmp( elem_key, key, key_size );
2100|        if ( flag == 0 )  return  start;
2101|        start ++;
2102|      }
2103|    }
2104|    else {
2105|      while ( start < last ) {
2106|        elem_key = *((void**)((char*)*start + key_offset));
2107|        flag = strcmp( (char*)elem_key, (char*)key );
2108|        if ( flag == 0 )  return  start;
2109|        start ++;
2110|      }
2111|    }
2112|  }
2113|
2114|  return  NULL;
2115|}
2116|
2117|
2118| 
2119|/**************************************************************************
2120|  11-4. <<< [ArrX_Imp_linearSearchPF] ポインタ配列を線形検索する(2) >>> 
2121|【引数】
2122|  ・void**  start;    ポインタ配列の先頭アドレス
2123|  ・void**  last;     ポインタ配列の末尾の次のアドレス
2124|  ・void*  key;       キーのアドレス
2125|  ・int  key_offset;  要素中のキーオフセット
2126|  ・void*  param;     判定関数に渡す任意のパラメータのアドレス
2127|  ・ArrX_CmpF  func;  判定関数のアドレス
2128|  ・int  返り値;      見つかった要素のアドレス、または NULL=見つからない
2129|【補足】
2130|・1つ見つかった後で、もう1つ見つけようとする場合、start に前に見つかった
2131|  要素の次の要素のアドレスを指定します。例:(type*)p + 1
2132|***************************************************************************/
2133|void*  ArrX_Imp_linearSearchPF( void** start, void** last,
2134|  const void* key, int key_offset, void* param, ArrX_CmpF func )
2135|{
2136|  int  flag;        /* 比較結果, memcmp 関数と同じ返り値 */
2137|  void*  elem_key;  /* 要素中のキーのアドレス */
2138|
2139|  while ( start < last ) {
2140|    elem_key = ((char*)*start + key_offset);
2141|    flag = (*func)( elem_key, (void*)key, param );
2142|    if ( flag == 0 )  return  start;
2143|    start ++;
2144|  }
2145|  return  NULL;
2146|}
2147|
2148|
2149| 
2150|/**************************************************************************
2151|  11-5. <<< [ArrX_Imp_cmpMatchMask] ワイルドカードによる文字列比較 >>> 
2152|【補足】
2153|・StrX_cmpWild 関数を ArrX_Imp_linearSearchF 関数で用いるための
2154|  ラッパーです。
2155|***************************************************************************/
2156|#ifdef USES_STRX
2157|int  ArrX_Imp_cmpMatchMask( char** a, char* b, void* dummy )
2158|{
2159|  return  StrX_cmpWild( *a, b );
2160|}
2161|#endif /* USES_STRX */
2162| 
2163|/**************************************************************************
2164|  11-6. <<< [ArrX_Imp_cmpIStr] 大文字小文字を区別しない文字列比較 >>> 
2165|【補足】
2166|・stricmp 関数を ArrX_Imp_linearSearchF 関数で用いるための
2167|s  ラッパーです。
2168|***************************************************************************/
2169|#ifndef ARRX_NO_STRICMP
2170|int  ArrX_Imp_cmpIStr( char** a, char* b, void* dummy )
2171|{
2172|  return  stricmp( *a, b );
2173|}
2174|#endif
2175| 
2176|