Annotation of parser3/src/types/pa_varray.h, revision 1.23
1.1 moko 1: /** @file
2: Parser: @b array parser type decl.
3:
4: Copyright (c) 2001-2023 Art. Lebedev Studio (http://www.artlebedev.com)
5: Authors: Konstantin Morshnev <moko@design.ru>, Alexandr Petrosian <paf@design.ru>
6: */
7:
8: #ifndef PA_VARRAY_H
9: #define PA_VARRAY_H
10:
1.23 ! moko 11: #define IDENT_PA_VARRAY_H "$Id: pa_varray.h,v 1.22 2024/10/28 13:05:14 moko Exp $"
1.1 moko 12:
13: #include "classes.h"
14: #include "pa_value.h"
15: #include "pa_array.h"
16: #include "pa_vhash.h"
17: #include "pa_vint.h"
18: #include "pa_globals.h"
19: #include "pa_symbols.h"
20:
21: // defines
22:
1.2 moko 23: #define VARRAY_TYPE "array"
1.15 moko 24: //#define DEBUG_ARRAY_USED
1.1 moko 25:
26: extern Methoded* array_class;
27:
1.2 moko 28: /// Sparse Array
29: template<typename T> class SparseArray: public Array<T> {
1.5 moko 30:
31: mutable size_t fused;
32:
1.2 moko 33: public:
1.5 moko 34: inline SparseArray(size_t initial=0) : Array<T>(initial), fused(0) {}
1.2 moko 35:
1.6 moko 36: inline SparseArray(size_t size, T* elements) : Array<T>(size), fused(size) {
1.16 moko 37: memcpy(this->felements, elements, size * sizeof(T));
1.6 moko 38: this->fsize=size;
39: }
40:
1.23 ! moko 41: void copy(SparseArray<T> &src) {
! 42: size_t size=src.fsize;
! 43: if(size){
! 44: fit(size-1);
! 45: memcpy(this->felements, src.felements, size * sizeof(T));
! 46: this->fsize=size;
! 47: fused=src.fused;
! 48: }
! 49: }
! 50:
! 51: // note: 'operator+=' is used directly from Array
1.17 moko 52:
53: void fit(size_t index);
54:
1.4 moko 55: inline T get(size_t index) const {
1.18 moko 56: return index < this->fsize ? this->felements[index] : NULL;
1.4 moko 57: }
58:
1.5 moko 59: inline void put(size_t index, T element){
60: this->fit(index);
1.2 moko 61: this->felements[index]=element;
1.5 moko 62: if(index >= this->fsize){
63: this->fsize=index+1;
64: }
65: }
66:
1.10 moko 67: inline bool put_dont_replace(size_t index, T element){
68: this->fit(index);
69: if(this->felements[index])
70: return true;
71: this->felements[index]=element;
72: if(index >= this->fsize){
73: this->fsize=index+1;
74: }
75: return false;
76: }
77:
1.5 moko 78: inline void insert(size_t index, T element) {
79: if(index >= this->fsize){
80: this->fit(index);
81: this->felements[index]=element;
82: this->fsize=index+1;
83: } else {
84: Array<T>::insert(index, element);
85: }
86: }
87:
88: size_t used() const{
1.15 moko 89: #ifndef DEBUG_ARRAY_USED
90: if(!fused)
91: #endif
92: {
93: size_t used=0;
1.5 moko 94: for(Array_iterator<T> i(*this); i;) {
95: if(i.next())
1.15 moko 96: used++;
1.5 moko 97: }
1.15 moko 98: #ifdef DEBUG_ARRAY_USED
99: if(fused && fused!=used)
100: throw Exception(PARSER_RUNTIME, 0, "cached elements count %d differs from actual %d", fused, used);
1.22 moko 101: printf(fused ? "cached used %d\n" : "counted used %d\n", used);
1.15 moko 102: #endif
103: fused=used;
1.5 moko 104: }
105: return fused;
106: }
107:
108: inline void clear(size_t index) {
1.18 moko 109: if(index < this->fsize){
1.5 moko 110: this->felements[index]=NULL;
1.18 moko 111: if(index == this->fsize-1){
1.7 moko 112: this->fsize--;
1.18 moko 113: locate_last_used();
1.14 moko 114: }
1.2 moko 115: }
116: }
1.5 moko 117:
118: inline void clear() { Array<T>::clear(); }
119:
1.8 moko 120: inline void remove(size_t index) {
1.18 moko 121: if(index < this->fsize){
1.8 moko 122: Array<T>::remove(index);
1.18 moko 123: if(index==this->fsize)
124: locate_last_used();
1.8 moko 125: }
126: }
127:
1.18 moko 128: inline T pop() {
129: if(this->fsize){
130: T result=this->felements[this->fsize-1];
131: this->fsize--;
132: locate_last_used();
133: return result;
134: }
135: return NULL;
136: }
137:
1.5 moko 138: inline void invalidate(){
139: fused=0;
140: }
141:
1.18 moko 142: inline void locate_last_used(){
143: for(;this->fsize>0 && !this->felements[this->fsize-1];this->fsize--);
144: }
145:
1.11 moko 146: inline void confirm_all_used(){
1.18 moko 147: fused=this->fsize;
1.11 moko 148: }
149:
1.19 moko 150: inline void change_used(int delta){
151: if(fused){
152: fused+=delta;
153: }
154: }
155:
1.15 moko 156: void compact(bool compact_undef){
1.13 moko 157: T* dst=this->felements;
158: T* elements_end=dst + this->fsize;
159:
1.15 moko 160: if(compact_undef){
161: for(T* src=this->felements; src < elements_end; src++)
162: if(*src && (*src)->is_defined())
163: *dst++=*src;
164: } else {
165: for(T* src=this->felements; src < elements_end; src++)
166: if(*src)
167: *dst++=*src;
168: }
169:
170: this->fsize=dst-this->felements;
1.13 moko 171: }
172:
1.2 moko 173: };
174:
175:
1.1 moko 176: class VArray: public VHashBase {
177: public: // value
178:
179: override const char* type() const { return VARRAY_TYPE; }
180: override VStateless_class *get_class() { return array_class; }
181:
1.5 moko 182: /// VArray: used elements count
183: override int as_int() const { return farray.used(); }
184: override double as_double() const { return farray.used(); }
1.22 moko 185: override bool is_defined() const { return farray.count()!=0; }
186: override bool as_bool() const { return farray.count()!=0; }
1.5 moko 187: override Value& as_expr_result() { return *new VInt(farray.used()); }
1.1 moko 188:
189: /// VArray: virtual hash
190: override HashStringValue *get_hash() { return &hash(); }
191: override HashStringValue* get_fields() { return &hash(); }
192: override HashStringValue* get_fields_reference() { return &hash(); }
193:
194: /// VArray: json-string
195: override const String* get_json_string(Json_options& options);
196:
197: /// VArray: (key)=value
198: override Value* get_element(const String& aname) {
199: #if !defined(FEATURE_GET_ELEMENT4CALL) || !defined(OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL)
200: // $method, CLASS, CLASS_NAME
201: if(Value* result=VStateless_object::get_element(aname))
202: return result;
203: #endif
1.20 moko 204: // $element, here as index() allows only numbers
205: if(Value* result=farray.get(index(aname)))
206: return result;
207:
1.1 moko 208: return NULL;
209: }
210:
211: #ifdef FEATURE_GET_ELEMENT4CALL
212: override Value* get_element4call(const String& aname) {
213: // $method first
214: if(Value* result=VStateless_object::get_element(aname))
215: return result;
216:
217: // $element
1.12 moko 218: if(is_index(aname))
219: if(Value* result=farray.get(index(aname)))
220: return result;
1.1 moko 221:
222: return bark("%s method not found", &aname);
223: }
224: #endif
225:
226: /// VArray: (key)=value
227: override const VJunction* put_element(const String& aname, Value* avalue) {
1.5 moko 228: farray.put(index(aname), avalue);
1.14 moko 229: farray.invalidate();
1.1 moko 230: return 0;
231: }
232:
233: public: // VHashBase
234:
235: override HashStringValue& hash();
236: override void set_default(Value*) { }
237: override Value* get_default() { return 0; }
1.5 moko 238: override void add(Value* avalue) { farray+=avalue; /* only json uses it, thus no need to invalidate()*/ }
1.1 moko 239:
240: public: // usage
241:
1.14 moko 242: VArray(size_t initial=0): farray(initial) {}
243: VArray(size_t size, Value** elements): farray(size, elements) {}
1.1 moko 244:
245: ArrayValue &array() { return farray; }
246:
247: static size_t index(int aindex){
248: if(aindex<0)
1.21 moko 249: throw Exception("number.format", 0, "index is out of range (negative)");
1.1 moko 250: return aindex;
251: }
252:
1.7 moko 253: static size_t index(const String::Body& aindex){ return pa_atoui(aindex.cstr()); }
254: static size_t index(const String& aindex){ return pa_atoui(aindex.cstr(), 10, &aindex); }
1.1 moko 255:
1.12 moko 256: static bool is_index(const String& aindex){
1.20 moko 257: for(const char *pos=aindex.cstr(); *pos ;pos++){
1.12 moko 258: if ((*pos < '0') || (*pos > '9'))
259: return false;
260: }
261: return true;
262: }
263:
1.5 moko 264: bool contains(size_t index){
265: return farray.get(index) != NULL;
1.1 moko 266: }
267:
268: private:
269:
270: ArrayValue farray;
271:
272: };
273:
274: #endif
E-mail: