ByteQueue.java
     1: //========================================================================================
     2: //  ByteQueue.java
     3: //    en:Byte queue
     4: //    ja:バイトキュー
     5: //  Copyright (C) 2003-2024 Makoto Kamada
     6: //
     7: //  This file is part of the XEiJ (X68000 Emulator in Java).
     8: //  You can use, modify and redistribute the XEiJ if the conditions are met.
     9: //  Read the XEiJ License for more details.
    10: //  https://stdkmd.net/xeij/
    11: //========================================================================================
    12: 
    13: package xeij;
    14: 
    15: public class ByteQueue {
    16: 
    17:   static final class Block {
    18:     volatile Block p = null;  //前のブロック。先頭のブロックの方向のリンク。null=先頭のブロック
    19:     volatile Block n = null;  //後のブロック。末尾のブロックの方向のリンク。null=末尾のブロック
    20: 
    21:     final int s = 1 << 12;  //配列のバイト数。2の累乗
    22:     final byte[] a = new byte[s];  //配列
    23:     volatile long w = 0;  //書き込んだバイト数
    24:     volatile long r = w;  //読み出したバイト数
    25:     //  a[(int)w&(s-1)]  書き込む位置
    26:     //  a[(int)r&(s-1)]  読み出す位置
    27:     //  r+s-w            書き込めるバイト数
    28:     //  w-r              読み出せるバイト数
    29:     //  w==r+s           満
    30:     //  r==w             空
    31:     //  0<=w-r<=s
    32:     //  r<=w<=r+s
    33: 
    34:     //clear ()
    35:     //  空にする。読み飛ばしたバイト数を返す
    36:     int clear () {
    37:       return skip (used ());
    38:     }  //clear
    39: 
    40:     //data = read ()
    41:     //  1バイト読み出して0x00~0xffの範囲で返す。-1=空
    42:     int read () {
    43:       return r != w ? a[(int) (r++) & (s - 1)] & 0xff : -1;
    44:     }  //read
    45: 
    46:     //read (array, offset, length)
    47:     //  配列へ読み出す。読み出せたバイト数を返す
    48:     int read (byte[] array, int offset, int length) {
    49:       length = Math.min (length, (int) (w - r));  //読み出せるバイト数
    50:       int offset0 = offset;
    51:       for (;;) {
    52:         int k = Math.min (length, s - ((int) r & (s - 1)));  //読み出す位置から末尾までのバイト数
    53:         if (k == 0) {
    54:           return offset - offset0;
    55:         }
    56:         System.arraycopy (a, (int) r & (s - 1),
    57:                           array, offset,
    58:                           k);
    59:         r += k;
    60:         offset += k;
    61:         length -= k;
    62:       }
    63:     }  //read
    64: 
    65:     //skip (length)
    66:     //  読み飛ばす。読み飛ばせた長さを返す
    67:     int skip (int length) {
    68:       length = Math.min (length, (int) (w - r));  //読み飛ばせるバイト数
    69:       r += length;
    70:       return length;
    71:     }  //skip
    72: 
    73:     //length = unused ()
    74:     //  書き込めるバイト数を返す。0=満
    75:     int unused () {
    76:       return (int) (r + s - w);
    77:     }  //unused
    78: 
    79:     //length = used ()
    80:     //  読み出せるバイト数を返す。0=空
    81:     int used () {
    82:       return (int) (w - r);
    83:     }  //used
    84: 
    85:     //length = write (data)
    86:     //  1バイト書き込む。書き込めたバイト数を返す
    87:     int write (int data) {
    88:       if (w == r + s) {
    89:         return 0;
    90:       }
    91:       a[(int) (w++) & (s - 1)] = (byte) data;
    92:       return 1;
    93:     }  //write
    94: 
    95:     //write (array, offset, length)
    96:     //  配列から書き込む。書き込めたバイト数を返す
    97:     int write (byte[] array, int offset, int length) {
    98:       length = Math.min (length, (int) (r + s - w));  //書き込めるバイト数
    99:       int offset0 = offset;
   100:       for (;;) {
   101:         int k = Math.min (length, s - ((int) w & (s - 1)));  //書き込む位置から末尾までのバイト数
   102:         if (k == 0) {
   103:           return offset - offset0;
   104:         }
   105:         System.arraycopy (array, offset,
   106:                           a, (int) w & (s - 1),
   107:                           k);
   108:         w += k;
   109:         offset += k;
   110:         length -= k;
   111:       }
   112:     }  //write
   113: 
   114:   }  //class Block
   115: 
   116:   volatile Block h = new Block ();  //先頭のブロック。次に読み出すブロック。h.p==null
   117:   volatile Block t = h;  //末尾のブロック。次に書き込むブロック。t.n==null
   118: 
   119:   final int s = 0x7fffffff;  //上限のバイト数
   120:   volatile long w = 0;  //書き込んだバイト数
   121:   volatile long r = w;  //読み出したバイト数
   122:   //  r+s-w            書き込めるバイト数
   123:   //  w-r              読み出せるバイト数
   124:   //  w==r+s           満
   125:   //  r==w             空
   126:   //  0<=w-r<=s
   127:   //  r<=w<=r+s
   128: 
   129:   //clear ()
   130:   //  空にする。読み飛ばしたバイト数を返す
   131:   int clear () {
   132:     return skip (used ());
   133:   }  //clear
   134: 
   135:   //data = read ()
   136:   //  1バイト読み出して0x00~0xffの範囲で返す。-1=空
   137:   int read () {
   138:     int data = h.read ();
   139:     if (data < 0) {
   140:       if (h == t) {
   141:         return data;
   142:       }
   143:       Block n = h.n;
   144:       n.p = null;
   145:       h.n = null;
   146:       h = n;
   147:       data = h.read ();
   148:     }
   149:     r++;
   150:     return data;
   151:   }  //read
   152: 
   153:   //read (array, offset, length)
   154:   //  配列へ読み出す。読み出せたバイト数を返す
   155:   int read (byte[] array, int offset, int length) {
   156:     //length = Math.min (length, (int) (w - r));  //読み出せるバイト数
   157:     long r0 = r;
   158:     int k = h.read (array, offset, length);
   159:     r += k;
   160:     offset += k;
   161:     length -= k;
   162:     while (length != 0) {
   163:       if (h == t) {
   164:         return (int) (r - r0);
   165:       }
   166:       Block n = h.n;
   167:       n.p = null;
   168:       h.n = null;
   169:       h = n;
   170:       k = h.read (array, offset, length);
   171:       r += k;
   172:       offset += k;
   173:       length -= k;
   174:     }
   175:     return (int) (r - r0);
   176:   }  //read
   177: 
   178:   //skip (length)
   179:   //  読み飛ばす。読み飛ばせた長さを返す
   180:   int skip (int length) {
   181:     //length = Math.min (length, (int) (w - r));  //読み出せるバイト数
   182:     long r0 = r;
   183:     int k = h.skip (length);
   184:     r += k;
   185:     length -= k;
   186:     while (length != 0) {
   187:       if (h == t) {
   188:         return (int) (r - r0);
   189:       }
   190:       Block n = h.n;
   191:       n.p = null;
   192:       h.n = null;
   193:       h = n;
   194:       k = h.skip (length);
   195:       r += k;
   196:       length -= k;
   197:     }
   198:     return (int) (r - r0);
   199:   }  //skip
   200: 
   201:   //length = unused ()
   202:   //  書き込めるバイト数を返す。0=満
   203:   int unused () {
   204:     return (int) (r + s - w);
   205:   }  //unused
   206: 
   207:   //length = used ()
   208:   //  読み出せるバイト数を返す。0=空
   209:   int used () {
   210:     return (int) (w - r);
   211:   }  //used
   212: 
   213:   //length = write (data)
   214:   //  1バイト書き込む。書き込めたバイト数を返す
   215:   int write (int data) {
   216:     if (w == r + s) {
   217:       return 0;
   218:     }
   219:     if (t.write (data) == 0) {
   220:       Block n = new Block ();
   221:       n.p = t;
   222:       t.n = n;
   223:       t = n;
   224:       t.write (data);
   225:     }
   226:     w++;
   227:     return 1;
   228:   }  //write
   229: 
   230:   //write (array, offset, length)
   231:   //  配列から書き込む。書き込めたバイト数を返す
   232:   int write (byte[] array, int offset, int length) {
   233:     length = Math.min (length, (int) (r + s - w));  //書き込めるバイト数
   234:     long w0 = w;
   235:     int k = t.write (array, offset, length);
   236:     w += k;
   237:     offset += k;
   238:     length -= k;
   239:     while (length != 0) {
   240:       Block n = new Block ();
   241:       n.p = t;
   242:       t.n = n;
   243:       t = n;
   244:       k = t.write (array, offset, length);
   245:       w += k;
   246:       offset += k;
   247:       length -= k;
   248:     }
   249:     return (int) (w - w0);
   250:   }  //write
   251: 
   252: }  //class ByteQueue