Annotation of parser3/src/types/pa_varray.h, revision 1.19
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.19 ! moko 11: #define IDENT_PA_VARRAY_H "$Id: pa_varray.h,v 1.18 2024/10/27 12:24:49 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.17 moko 41: // note: 'append' and 'operator+=' are used directly from Array.
42:
43: // not virtual, thus Array::append does not use it, but that's OK.
44: void fit(size_t index);
45:
1.4 moko 46: inline T get(size_t index) const {
1.18 moko 47: return index < this->fsize ? this->felements[index] : NULL;
1.4 moko 48: }
49:
1.5 moko 50: inline void put(size_t index, T element){
51: this->fit(index);
1.2 moko 52: this->felements[index]=element;
1.5 moko 53: if(index >= this->fsize){
54: this->fsize=index+1;
55: }
56: }
57:
1.10 moko 58: inline bool put_dont_replace(size_t index, T element){
59: this->fit(index);
60: if(this->felements[index])
61: return true;
62: this->felements[index]=element;
63: if(index >= this->fsize){
64: this->fsize=index+1;
65: }
66: return false;
67: }
68:
1.5 moko 69: inline void insert(size_t index, T element) {
70: if(index >= this->fsize){
71: this->fit(index);
72: this->felements[index]=element;
73: this->fsize=index+1;
74: } else {
75: Array<T>::insert(index, element);
76: }
77: }
78:
79: size_t used() const{
1.15 moko 80: #ifndef DEBUG_ARRAY_USED
81: if(!fused)
82: #endif
83: {
84: size_t used=0;
1.5 moko 85: for(Array_iterator<T> i(*this); i;) {
86: if(i.next())
1.15 moko 87: used++;
1.5 moko 88: }
1.15 moko 89: #ifdef DEBUG_ARRAY_USED
90: if(fused && fused!=used)
91: throw Exception(PARSER_RUNTIME, 0, "cached elements count %d differs from actual %d", fused, used);
1.19 ! moko 92: printf(fused ? "cached used %d\n":"counted used %d\n", used);
1.15 moko 93: #endif
94: fused=used;
1.5 moko 95: }
96: return fused;
97: }
98:
99: inline void clear(size_t index) {
1.18 moko 100: if(index < this->fsize){
1.5 moko 101: this->felements[index]=NULL;
1.18 moko 102: if(index == this->fsize-1){
1.7 moko 103: this->fsize--;
1.18 moko 104: locate_last_used();
1.14 moko 105: }
1.2 moko 106: }
107: }
1.5 moko 108:
109: inline void clear() { Array<T>::clear(); }
110:
1.8 moko 111: inline void remove(size_t index) {
1.18 moko 112: if(index < this->fsize){
1.8 moko 113: Array<T>::remove(index);
1.18 moko 114: if(index==this->fsize)
115: locate_last_used();
1.8 moko 116: }
117: }
118:
1.18 moko 119: inline T pop() {
120: if(this->fsize){
121: T result=this->felements[this->fsize-1];
122: this->fsize--;
123: locate_last_used();
124: return result;
125: }
126: return NULL;
127: }
128:
1.5 moko 129: inline void invalidate(){
130: fused=0;
131: }
132:
1.18 moko 133: inline void locate_last_used(){
134: for(;this->fsize>0 && !this->felements[this->fsize-1];this->fsize--);
135: }
136:
1.11 moko 137: inline void confirm_all_used(){
1.18 moko 138: fused=this->fsize;
1.11 moko 139: }
140:
1.19 ! moko 141: inline void change_used(int delta){
! 142: if(fused){
! 143: fused+=delta;
! 144: }
! 145: }
! 146:
1.15 moko 147: void compact(bool compact_undef){
1.13 moko 148: T* dst=this->felements;
149: T* elements_end=dst + this->fsize;
150:
1.15 moko 151: if(compact_undef){
152: for(T* src=this->felements; src < elements_end; src++)
153: if(*src && (*src)->is_defined())
154: *dst++=*src;
155: } else {
156: for(T* src=this->felements; src < elements_end; src++)
157: if(*src)
158: *dst++=*src;
159: }
160:
161: this->fsize=dst-this->felements;
1.13 moko 162: }
163:
1.2 moko 164: };
165:
166:
1.1 moko 167: class VArray: public VHashBase {
168: public: // value
169:
170: override const char* type() const { return VARRAY_TYPE; }
171: override VStateless_class *get_class() { return array_class; }
172:
1.5 moko 173: /// VArray: used elements count
174: override int as_int() const { return farray.used(); }
175: override double as_double() const { return farray.used(); }
176: override bool is_defined() const { return farray.used()!=0; }
177: override bool as_bool() const { return farray.used()!=0; }
178: override Value& as_expr_result() { return *new VInt(farray.used()); }
1.1 moko 179:
180: /// VArray: virtual hash
181: override HashStringValue *get_hash() { return &hash(); }
182: override HashStringValue* get_fields() { return &hash(); }
183: override HashStringValue* get_fields_reference() { return &hash(); }
184:
185: /// VArray: json-string
186: override const String* get_json_string(Json_options& options);
187:
188: /// VArray: (key)=value
189: override Value* get_element(const String& aname) {
190: // $element first
1.4 moko 191: if(Value* result=farray.get(index(aname)))
1.1 moko 192: return result;
193:
194: // $fields -- pseudo field to make 'hash' and 'array' more like 'table'
195: if(SYMBOLS_EQ(aname,FIELDS_SYMBOL))
196: return this;
197:
198: #if !defined(FEATURE_GET_ELEMENT4CALL) || !defined(OPTIMIZE_BYTECODE_GET_ELEMENT__SPECIAL)
199: // $method, CLASS, CLASS_NAME
200: if(Value* result=VStateless_object::get_element(aname))
201: return result;
202: #endif
203: return NULL;
204: }
205:
206: #ifdef FEATURE_GET_ELEMENT4CALL
207: override Value* get_element4call(const String& aname) {
208: // $method first
209: if(Value* result=VStateless_object::get_element(aname))
210: return result;
211:
212: // $element
1.12 moko 213: if(is_index(aname))
214: if(Value* result=farray.get(index(aname)))
215: return result;
1.1 moko 216:
217: return bark("%s method not found", &aname);
218: }
219: #endif
220:
221: /// VArray: (key)=value
222: override const VJunction* put_element(const String& aname, Value* avalue) {
1.5 moko 223: farray.put(index(aname), avalue);
1.14 moko 224: farray.invalidate();
1.1 moko 225: return 0;
226: }
227:
228: public: // VHashBase
229:
230: override HashStringValue& hash();
231: override void set_default(Value*) { }
232: override Value* get_default() { return 0; }
1.5 moko 233: override void add(Value* avalue) { farray+=avalue; /* only json uses it, thus no need to invalidate()*/ }
1.1 moko 234:
235: public: // usage
236:
1.14 moko 237: VArray(size_t initial=0): farray(initial) {}
238: VArray(size_t size, Value** elements): farray(size, elements) {}
1.1 moko 239:
240: ArrayValue &array() { return farray; }
241:
242: static size_t index(int aindex){
243: if(aindex<0)
1.9 moko 244: throw Exception("number.format", 0, "index out of range (negative)");
1.1 moko 245: return aindex;
246: }
247:
1.7 moko 248: static size_t index(const String::Body& aindex){ return pa_atoui(aindex.cstr()); }
249: static size_t index(const String& aindex){ return pa_atoui(aindex.cstr(), 10, &aindex); }
1.1 moko 250:
1.12 moko 251: static bool is_index(const String& aindex){
252: for(const char *pos=aindex.cstr();*pos;pos++){
253: if ((*pos < '0') || (*pos > '9'))
254: return false;
255: }
256: return true;
257: }
258:
1.5 moko 259: bool contains(size_t index){
260: return farray.get(index) != NULL;
1.1 moko 261: }
262:
263: private:
264:
265: ArrayValue farray;
266:
267: };
268:
269: #endif
E-mail: