Annotation of parser3/src/classes/hash.C, revision 1.48
1.1 paf 1: /** @file
2: Parser: @b hash parser class.
3:
1.34 paf 4: Copyright (c) 2001, 2002 ArtLebedev Group (http://www.artlebedev.com)
1.35 paf 5: Author: Alexandr Petrosian <paf@design.ru> (http://paf.design.ru)
1.41 paf 6: */
1.1 paf 7:
1.48 ! paf 8: static const char* IDENT_HASH_C="$Date: 2002/09/17 08:48:35 $";
1.1 paf 9:
10: #include "classes.h"
11: #include "pa_request.h"
12: #include "pa_vhash.h"
1.6 parser 13: #include "pa_vvoid.h"
1.2 parser 14: #include "pa_sql_connection.h"
1.9 parser 15: #include "pa_vtable.h"
1.22 parser 16: #include "pa_vbool.h"
1.26 paf 17: #include "pa_vmethod_frame.h"
1.2 parser 18:
1.1 paf 19: // class
20:
21: class MHash : public Methoded {
1.2 parser 22: public: // VStateless_class
23: Value *create_new_value(Pool& pool) { return new(pool) VHash(pool); }
24:
1.1 paf 25: public:
26: MHash(Pool& pool);
27: public: // Methoded
1.2 parser 28: bool used_directly() { return true; }
1.1 paf 29: };
30:
31: // methods
32:
1.11 parser 33: #ifndef DOXYGEN
34: class Hash_sql_event_handlers : public SQL_Driver_query_event_handlers {
35: public:
36: Hash_sql_event_handlers(Pool& apool, const String& amethod_name,
37: const String& astatement_string, const char *astatement_cstr,
38: Hash& arows_hash) :
39: pool(apool),
40: method_name(amethod_name),
41: statement_string(astatement_string),
42: statement_cstr(astatement_cstr),
43: rows_hash(arows_hash),
44: columns(pool),
45: row_index(0) {
46: }
47: void add_column(void *ptr, size_t size) {
48: String *column=new(pool) String(pool);
49: column->APPEND_TAINTED(
50: (const char *)ptr, size,
51: statement_cstr, 0);
52: columns+=column;
53: }
54: void before_rows() {
55: if(columns.size()<=1)
1.36 paf 56: throw Exception("parser.runtime",
1.11 parser 57: &method_name,
58: "column count must be more than 1 to create a hash");
59: }
60: void add_row() {
61: column_index=0;
62: }
63: void add_row_cell(void *ptr, size_t size) {
64: String *cell=new(pool) String(pool);
65: if(size)
66: cell->APPEND_TAINTED(
67: (const char *)ptr, size,
68: statement_cstr, row_index++);
69: if(column_index==0) {
70: VHash *row_vhash=new(pool) VHash(pool);
1.24 parser 71: row_hash=row_vhash->get_hash(0);
1.48 ! paf 72: if(rows_hash.put_dont_replace(*cell, row_vhash)) // put. existed?
! 73: throw Exception("parser.runtime",
! 74: cell,
! 75: "duplicate key");
1.11 parser 76: } else
77: row_hash->put(*columns.get_string(column_index), new(pool) VString(*cell));
1.12 parser 78: column_index++;
1.11 parser 79: }
80:
81: private:
82: Pool& pool;
83: const String& method_name;
84: const String& statement_string; const char *statement_cstr;
85: Hash& rows_hash;
86: Hash *row_hash;
87: int column_index;
88: Array columns;
89: int row_index;
90: };
91: #endif
92:
1.22 parser 93: static void copy_all_overwrite_to(const Hash::Key& key, Hash::Val *value, void *info) {
1.20 parser 94: Hash& dest=*static_cast<Hash *>(info);
95: dest.put(key, value);
96: }
1.22 parser 97: static void _create_or_add(Request& r, const String& method_name, MethodParams *params) {
1.20 parser 98: Pool& pool=r.pool();
99:
100: if(params->size()) {
1.22 parser 101: Value& vb=params->as_no_junction(0, "param must be hash");
1.24 parser 102: if(Hash *b=vb.get_hash(&method_name))
1.28 paf 103: b->for_each(copy_all_overwrite_to, &static_cast<VHash *>(r.self)->hash(&method_name));
1.20 parser 104: }
105: }
106:
1.22 parser 107: static void remove_key_from(const Hash::Key& key, Hash::Val *value, void *info) {
108: Hash& dest=*static_cast<Hash *>(info);
1.25 paf 109: dest.remove(key);
1.22 parser 110: }
111: static void _sub(Request& r, const String& method_name, MethodParams *params) {
112: Pool& pool=r.pool();
113:
114: Value& vb=params->as_no_junction(0, "param must be hash");
1.24 parser 115: if(Hash *b=vb.get_hash(&method_name))
1.28 paf 116: b->for_each(remove_key_from, &static_cast<VHash *>(r.self)->hash(&method_name));
1.22 parser 117: }
118:
119: static void copy_all_dontoverwrite_to(const Hash::Key& key, Hash::Val *value, void *info) {
120: Hash& dest=*static_cast<Hash *>(info);
121: dest.put_dont_replace(key, value);
122: }
123: static void _union(Request& r, const String& method_name, MethodParams *params) {
124: Pool& pool=r.pool();
125:
126: // dest = copy of self
1.28 paf 127: Hash& dest=*new(pool) Hash(static_cast<VHash *>(r.self)->hash(&method_name));
1.22 parser 128: // dest += b
129: Value& vb=params->as_no_junction(0, "param must be hash");
1.24 parser 130: if(Hash *b=vb.get_hash(&method_name))
1.22 parser 131: b->for_each(copy_all_dontoverwrite_to, &dest);
132:
133: // return result
134: Value& result=*new(pool) VHash(pool, dest);
135: r.write_no_lang(result);
136: }
137:
138: #ifndef DOXYGEN
139: struct Copy_intersection_to_info {
140: Hash *b;
141: Hash *dest;
142: };
143: #endif
144:
145: static void copy_intersection_to(const Hash::Key& key, Hash::Val *value, void *info) {
146: Copy_intersection_to_info& i=*static_cast<Copy_intersection_to_info *>(info);
147:
148: if(i.b->get(key))
149: i.dest->put_dont_replace(key, value);
150: }
151: static void _intersection(Request& r, const String& method_name, MethodParams *params) {
152: Pool& pool=r.pool();
153:
154: // dest = copy of self
155: Hash& dest=*new(pool) Hash(pool);
156: // dest += b
157: Value& vb=params->as_no_junction(0, "param must be hash");
1.24 parser 158: if(Hash *b=vb.get_hash(&method_name)) {
1.22 parser 159: Copy_intersection_to_info info={
160: b,
161: &dest
162: };
1.28 paf 163: static_cast<VHash *>(r.self)->hash(&method_name).for_each(copy_intersection_to, &info);
1.22 parser 164: }
165:
166: // return result
1.39 paf 167: r.write_no_lang(*new(pool) VHash(pool, dest));
1.22 parser 168: }
169:
170: static void *intersects(const Hash::Key& key, Hash::Val *value, void *info) {
171: return static_cast<Hash *>(info)->get(key);
172: }
173:
174: static void _intersects(Request& r, const String& method_name, MethodParams *params) {
175: Pool& pool=r.pool();
176:
177: bool yes=false;
178:
179: // dest = copy of self
180: Hash& dest=*new(pool) Hash(pool);
181: // dest += b
182: Value& vb=params->as_no_junction(0, "param must be hash");
1.24 parser 183: if(Hash *b=vb.get_hash(&method_name))
1.28 paf 184: yes=static_cast<VHash *>(r.self)->hash(&method_name).first_that(intersects, b)!=0;
1.22 parser 185:
186: // return result
1.39 paf 187: r.write_no_lang(*new(pool) VBool(pool, yes));
1.22 parser 188: }
189:
190:
1.2 parser 191: static void _sql(Request& r, const String& method_name, MethodParams *params) {
192: Pool& pool=r.pool();
193:
1.10 parser 194: Value& statement=params->as_junction(0, "statement must be code");
1.2 parser 195:
196: ulong limit=0;
1.33 paf 197: ulong offset=0;
1.2 parser 198: if(params->size()>1) {
1.33 paf 199: Value& voptions=params->as_no_junction(1, "options must be hash, not code");
1.43 paf 200: if(!voptions.is_string())
1.33 paf 201: if(Hash *options=voptions.get_hash(&method_name)) {
202: if(Value *vlimit=(Value *)options->get(*sql_limit_name))
1.37 paf 203: limit=(ulong)r.process_to_value(*vlimit).as_double();
1.33 paf 204: if(Value *voffset=(Value *)options->get(*sql_offset_name))
1.37 paf 205: offset=(ulong)r.process_to_value(*voffset).as_double();
1.33 paf 206: } else
1.36 paf 207: throw Exception("parser.runtime",
1.33 paf 208: &method_name,
209: "options must be hash");
1.2 parser 210: }
211:
212: Temp_lang temp_lang(r, String::UL_SQL);
1.37 paf 213: const String& statement_string=r.process_to_string(statement);
1.2 parser 214: const char *statement_cstr=
1.32 paf 215: statement_string.cstr(String::UL_UNSPECIFIED, r.connection(&method_name));
1.28 paf 216: Hash& hash=static_cast<VHash *>(r.self)->hash(&method_name);
1.11 parser 217: hash.clear();
218: Hash_sql_event_handlers handlers(pool, method_name,
219: statement_string, statement_cstr, hash);
1.23 parser 220:
1.32 paf 221: r.connection(&method_name)->query(
1.23 parser 222: statement_cstr, offset, limit,
1.45 paf 223: handlers,
224: statement_string);
1.2 parser 225: }
226:
1.9 parser 227: static void keys_collector(const Hash::Key& key, Hash::Val *value, void *info) {
228: Table& table=*static_cast<Table *>(info);
229: Pool& pool=table.pool();
230:
231: Array& row=*new(pool) Array(pool);
232: row+=&key;
233: table+=&row;
234: }
235: static void _keys(Request& r, const String& method_name, MethodParams *) {
236: Pool& pool=r.pool();
237:
238: Array& columns=*new(pool) Array(pool);
239: columns+=new(pool) String(pool, "key");
240: Table& table=*new(pool) Table(pool, &method_name, &columns);
241:
1.28 paf 242: static_cast<VHash *>(r.self)->hash(&method_name).for_each(keys_collector, &table);
1.9 parser 243:
1.39 paf 244: r.write_no_lang(*new(pool) VTable(pool, &table));
1.9 parser 245: }
246:
1.16 parser 247: static void _count(Request& r, const String& method_name, MethodParams *) {
248: Pool& pool=r.pool();
249:
1.39 paf 250: r.write_no_lang(
251: *new(pool) VInt(pool, static_cast<VHash *>(r.self)->hash(&method_name).size()));
1.16 parser 252: }
253:
1.25 paf 254: static void _delete(Request& r, const String& method_name, MethodParams *params) {
255: Pool& pool=r.pool();
256:
1.28 paf 257: static_cast<VHash *>(r.self)->hash(&method_name).remove(params->as_string(0, "key must be string"));
1.25 paf 258: }
259:
1.26 paf 260: #ifndef DOXYGEN
261: struct Foreach_info {
262: Request *r;
263: const String* key_var_name;
264: const String* value_var_name;
265: Value *body_code;
266: Value *delim_maybe_code;
267:
268: VString *vkey;
269: bool need_delim;
270: };
271: #endif
272:
273: static void one_foreach_cycle(const Hash::Key& akey, Hash::Val *avalue,
274: void *info) {
275: Foreach_info& i=*static_cast<Foreach_info *>(info);
276:
277: i.vkey->set_string(akey);
1.46 paf 278: i.r->method_frame->put_element(*i.key_var_name, i.vkey, false);
279: i.r->method_frame->put_element(*i.value_var_name, static_cast<Value *>(avalue), false);
1.26 paf 280:
1.47 paf 281: StringOrValue sv_processed=i.r->process(*i.body_code);
282: const String *s_processed=sv_processed.get_string();
283: if(i.delim_maybe_code && s_processed && s_processed->size()) { // delimiter set and we have body
284: if(i.need_delim) // need delim & iteration produced string?
1.38 paf 285: i.r->write_pass_lang(i.r->process(*i.delim_maybe_code));
1.26 paf 286: i.need_delim=true;
287: }
1.47 paf 288: i.r->write_pass_lang(sv_processed);
1.26 paf 289: }
290: static void _foreach(Request& r, const String& method_name, MethodParams *params) {
291: Pool& pool=r.pool();
292: const String& key_var_name=params->as_string(0, "key-var name must be string");
293: const String& value_var_name=params->as_string(1, "value-var name must be string");
294: Value& body_code=params->as_junction(2, "body must be code");
295: Value *delim_maybe_code=params->size()>3?¶ms->get(3):0;
296:
297: Foreach_info info={
298: &r,
299: &key_var_name, &value_var_name,
300: &body_code,
301: delim_maybe_code,
302:
303: new(pool) VString(pool),
304: false
305: };
1.28 paf 306: VHash& self=*static_cast<VHash *>(r.self);
307: Hash& hash=self.hash(&method_name);
308: VHash_lock lock(self);
309: hash.for_each(one_foreach_cycle, &info);
1.26 paf 310: }
311:
1.1 paf 312: // constructor
313:
1.39 paf 314: MHash::MHash(Pool& apool) : Methoded(apool, "hash")
315: {
1.21 parser 316: // ^hash::create[[copy_from]]
1.22 parser 317: add_native_method("create", Method::CT_DYNAMIC, _create_or_add, 0, 1);
318: // ^hash.add[add_from]
319: add_native_method("add", Method::CT_DYNAMIC, _create_or_add, 1, 1);
320: // ^hash.sub[sub_from]
321: add_native_method("sub", Method::CT_DYNAMIC, _sub, 1, 1);
322: // ^a.union[b] = hash
323: add_native_method("union", Method::CT_DYNAMIC, _union, 1, 1);
324: // ^a.intersection[b] = hash
325: add_native_method("intersection", Method::CT_DYNAMIC, _intersection, 1, 1);
326: // ^a.intersects[b] = bool
327: add_native_method("intersects", Method::CT_DYNAMIC, _intersects, 1, 1);
1.25 paf 328:
329: // ^a.delete[key]
330: add_native_method("delete", Method::CT_DYNAMIC, _delete, 1, 1);
1.2 parser 331:
1.33 paf 332: // ^hash:sql[query][$.limit(1) $.offset(2)]
333: add_native_method("sql", Method::CT_DYNAMIC, _sql, 1, 2);
1.2 parser 334:
1.14 parser 335: // ^hash._keys[]
1.13 parser 336: add_native_method("_keys", Method::CT_DYNAMIC, _keys, 0, 0);
1.16 parser 337:
338: // ^hash._count[]
339: add_native_method("_count", Method::CT_DYNAMIC, _count, 0, 0);
1.26 paf 340:
341: // ^hash.foreach[key;value]{code}[delim]
342: add_native_method("foreach", Method::CT_DYNAMIC, _foreach, 2+1, 2+1+1);
1.1 paf 343: }
344:
345: // global variable
346:
1.40 paf 347: Methoded *hash_class;
1.1 paf 348:
349: // creator
350:
351: Methoded *MHash_create(Pool& pool) {
1.40 paf 352: return hash_class=new(pool) MHash(pool);
1.1 paf 353: }
E-mail: