File: dequeue.c

package info (click to toggle)
rscheme 0.7.2-1.1
  • links: PTS
  • area: main
  • in suites: slink
  • size: 10,672 kB
  • ctags: 12,430
  • sloc: lisp: 37,104; ansic: 29,763; cpp: 2,630; sh: 1,677; makefile: 568; yacc: 202; lex: 175; perl: 33
file content (190 lines) | stat: -rw-r--r-- 4,704 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
/*-----------------------------------------------------------------*-C-*---
 * File:    handc/runtime/dequeue.c
 *
 *          Copyright (C)1997 Donovan Kolbly <d.kolbly@rscheme.org>
 *          as part of the RScheme project, licensed for free use.
 *          See <http://www.rscheme.org/> for the latest information.
 *
 * File version:     1.8
 * File mod date:    1997.11.29 23:10:50
 * System build:     v0.7.2, 97.12.21
 *
 *------------------------------------------------------------------------*/

#include <rscheme/scheme.h>
#include <rscheme/smemory.h>
#include <rscheme/allocns.h>

/*
 * example state:
 *
 *               0     1     2     3     4     5     6
 *            +-----+-----+-----+-----+-----+-----+-----+
 *            |     |     |  a  |  b  |  c  |     |     |
 *            +-----+-----+-----+-----+-----+-----+-----+
 *                        ^                 ^
 *                       front             back
 *                        =2                =5
 *   pop-front => a
 *   pop-back => c
 */

#define DEQ_STATE(deq)  gvec_ref((deq),SLOT(0))
#define DEQ_FRONT(deq)  gvec_ref((deq),SLOT(1))
#define DEQ_BACK(deq)  gvec_ref((deq),SLOT(2))

#define SET_DEQ_STATE(deq,s) gvec_set((deq),SLOT(0),(s))
#define SET_DEQ_FRONT(deq,f) gvec_write_non_ptr((deq),SLOT(1),(f))
#define SET_DEQ_BACK(deq,b) gvec_write_non_ptr((deq),SLOT(2),(b))

obj make_dequeue( void )
{
  return make3( dequeue_class, 
		make_gvec( vector_class, SLOT(5), FALSE_OBJ ),
		ZERO,
		ZERO );
}

rs_bool dequeue_empty( obj deq )
{
  return EQ(DEQ_FRONT(deq),DEQ_BACK(deq));
}

obj dequeue_count( obj deq )
{
  obj len;

  len = FX_SUB( DEQ_BACK(deq), DEQ_FRONT(deq) );
  if (FX_LT(len,ZERO))
    return FX_ADD( len, RIBYTES_TO_FXWORDS(SIZEOF_PTR(DEQ_STATE(deq))) );
  else
    return len;
}

static obj expanded_state( obj deq, UINT_32 expand_bytes )
{
  obj state, len = dequeue_count(deq);
  UINT_32 i, j, end, lim;
  obj result;

  result = alloc( expand_bytes + FXWORDS_TO_RIBYTES(len), vector_class );

  state = DEQ_STATE(deq);
  j = 0;
  i = FXWORDS_TO_RIBYTES(DEQ_FRONT(deq));
  end = FXWORDS_TO_RIBYTES(DEQ_BACK(deq));
  lim = SIZEOF_PTR(state);

  while (i != end)
    {
      gvec_write_init( result, j, gvec_ref( state, i ) );
      j += SLOT(1);
      i += SLOT(1);
      if (i >= lim)
	i = 0;
    }
  while (expand_bytes > 0)
    {
      gvec_write_init_non_ptr( result, j, FALSE_OBJ );
      j += SLOT(1);
      expand_bytes -= SLOT(1);
    }
  return result;
}

obj dequeue_state( obj deq )
{
  return expanded_state( deq, 0 );
}

static void expand( obj deq )
{
  obj len = dequeue_count(deq);
  
  SET_DEQ_STATE( deq, expanded_state( deq, SLOT(10) ) );
  SET_DEQ_FRONT( deq, ZERO );
  SET_DEQ_BACK( deq, len );
}

static obj succ( obj deq, obj i )
{
  i = ADD1(i);
  if (EQ(i,RIBYTES_TO_FXWORDS(SIZEOF_PTR(DEQ_STATE(deq)))))
    return ZERO;
  else
    return i;
}

static obj pred( obj deq, obj i )
{
  if (EQ(i,ZERO))
    i = RIBYTES_TO_FXWORDS(SIZEOF_PTR(DEQ_STATE(deq)));
  return SUB1(i);
}

static void dequeue_is_empty( char *op )
{
  scheme_error( "~a: <dequeue> is empty", 1, make_string(op) );
}

#define assert_ne(deq,op) if (dequeue_empty(deq)) dequeue_is_empty( op )

void dequeue_push_back( obj deq, obj item )
{
  obj oldb = DEQ_BACK(deq);
  obj newb;
  newb = succ( deq, oldb );
  if (EQ(newb,DEQ_FRONT(deq)))
    {
      expand(deq);
      dequeue_push_back( deq, item );
    }
  else
    {
      gvec_set( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(oldb), item );
      SET_DEQ_BACK( deq, newb );
    }
}

void dequeue_push_front( obj deq, obj item )
{
  obj oldf = DEQ_FRONT(deq);
  obj newf;
  newf = pred( deq, oldf );
  if (EQ(newf, DEQ_BACK(deq)))
    {
      expand(deq);
      dequeue_push_front( deq, item );
    }
  else
    {
      gvec_set( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(newf), item );
      SET_DEQ_FRONT( deq, newf );
    }
}

obj dequeue_pop_back( obj deq )
{
  obj item, newb, oldb = DEQ_BACK(deq);
  assert_ne(deq, "dequeue-pop-back!");
  newb = pred( deq, oldb );
  SET_DEQ_BACK( deq, newb );
  item = gvec_ref( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(newb) );
  /* clear the now-unused position in case there is a GC liveness issue
   * (ie, I was seeing annoying latencies finalizing threads in the
   * new threads system)
   */
  gvec_write_non_ptr( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(newb), FALSE_OBJ );
  return item;
}

obj dequeue_pop_front( obj deq )
{
  obj item, newf, oldf = DEQ_FRONT(deq);
  assert_ne(deq, "dequeue-pop-front!");
  newf = succ( deq, oldf );
  SET_DEQ_FRONT( deq, newf );
  item = gvec_ref( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(oldf) );
  gvec_write_non_ptr( DEQ_STATE(deq), FXWORDS_TO_RIBYTES(oldf), FALSE_OBJ );
  return item;
}