Skip to content

Commit ebdb98a

Browse files
committed
src: add iterator for Object
Refs: #830 Signed-off-by: Darshan Sen <darshan.sen@postman.com>
1 parent 4a3de56 commit ebdb98a

File tree

4 files changed

+214
-0
lines changed

4 files changed

+214
-0
lines changed

napi-inl.h

+85
Original file line numberDiff line numberDiff line change
@@ -1305,6 +1305,14 @@ inline Object::PropertyLValue<uint32_t> Object::operator [](uint32_t index) {
13051305
return PropertyLValue<uint32_t>(*this, index);
13061306
}
13071307

1308+
inline Object::PropertyLValue<Value> Object::operator[](Value index) {
1309+
return PropertyLValue<Value>(*this, index);
1310+
}
1311+
1312+
inline Object::PropertyLValue<Value> Object::operator[](Value index) const {
1313+
return PropertyLValue<Value>(*this, index);
1314+
}
1315+
13081316
inline MaybeOrValue<Value> Object::operator[](const char* utf8name) const {
13091317
return Get(utf8name);
13101318
}
@@ -1529,6 +1537,83 @@ inline void Object::AddFinalizer(Finalizer finalizeCallback,
15291537
}
15301538
}
15311539

1540+
#ifdef NAPI_CPP_EXCEPTIONS
1541+
inline Object::const_iterator::const_iterator(const Object* object,
1542+
const Type type) {
1543+
_object = object;
1544+
_keys = object->GetPropertyNames();
1545+
_index = type == Type::BEGIN ? 0 : _keys.Length();
1546+
}
1547+
1548+
inline Object::const_iterator Napi::Object::begin() const {
1549+
const_iterator it(this, Object::const_iterator::Type::BEGIN);
1550+
return it;
1551+
}
1552+
1553+
inline Object::const_iterator Napi::Object::end() const {
1554+
const_iterator it(this, Object::const_iterator::Type::END);
1555+
return it;
1556+
}
1557+
1558+
inline Object::const_iterator& Object::const_iterator::operator++() {
1559+
++_index;
1560+
return *this;
1561+
}
1562+
1563+
inline bool Object::const_iterator::operator==(
1564+
const const_iterator& other) const {
1565+
return _index == other._index;
1566+
}
1567+
1568+
inline bool Object::const_iterator::operator!=(
1569+
const const_iterator& other) const {
1570+
return _index != other._index;
1571+
}
1572+
1573+
inline std::pair<Value, Object::PropertyLValue<Value>>
1574+
Object::const_iterator::operator*() const {
1575+
Value key = _keys[_index];
1576+
const PropertyLValue<Value> value = (*_object)[key];
1577+
return {key, value};
1578+
}
1579+
1580+
inline Object::iterator::iterator(Object* object, const Type type) {
1581+
_object = object;
1582+
_keys = object->GetPropertyNames();
1583+
_index = type == Type::BEGIN ? 0 : _keys.Length();
1584+
}
1585+
1586+
inline Object::iterator Napi::Object::begin() {
1587+
iterator it(this, Object::iterator::Type::BEGIN);
1588+
return it;
1589+
}
1590+
1591+
inline Object::iterator Napi::Object::end() {
1592+
iterator it(this, Object::iterator::Type::END);
1593+
return it;
1594+
}
1595+
1596+
inline Object::iterator& Object::iterator::operator++() {
1597+
++_index;
1598+
return *this;
1599+
}
1600+
1601+
inline bool Object::iterator::operator==(const iterator& other) const {
1602+
return _index == other._index;
1603+
}
1604+
1605+
inline bool Object::iterator::operator!=(const iterator& other) const {
1606+
return _index != other._index;
1607+
}
1608+
1609+
inline std::pair<Value, Object::PropertyLValue<Value>>
1610+
Object::iterator::operator*() {
1611+
Value key = _keys[_index];
1612+
const PropertyLValue<Value> value = (*_object)[key];
1613+
return {key, value};
1614+
}
1615+
#endif // NAPI_CPP_EXCEPTIONS
1616+
15321617
#if NAPI_VERSION >= 8
15331618
inline MaybeOrValue<bool> Object::Freeze() {
15341619
napi_status status = napi_object_freeze(_env, _value);

napi.h

+71
Original file line numberDiff line numberDiff line change
@@ -741,6 +741,14 @@ namespace Napi {
741741
uint32_t index /// Property / element index
742742
);
743743

744+
/// Gets or sets an indexed property or array element.
745+
PropertyLValue<Value> operator[](Value index /// Property / element index
746+
);
747+
748+
/// Gets or sets an indexed property or array element.
749+
PropertyLValue<Value> operator[](Value index /// Property / element index
750+
) const;
751+
744752
/// Gets a named property.
745753
MaybeOrValue<Value> operator[](
746754
const char* utf8name ///< UTF-8 encoded null-terminated property name
@@ -928,6 +936,21 @@ namespace Napi {
928936
inline void AddFinalizer(Finalizer finalizeCallback,
929937
T* data,
930938
Hint* finalizeHint);
939+
940+
#ifdef NAPI_CPP_EXCEPTIONS
941+
class const_iterator;
942+
943+
inline const_iterator begin() const;
944+
945+
inline const_iterator end() const;
946+
947+
class iterator;
948+
949+
inline iterator begin();
950+
951+
inline iterator end();
952+
#endif // NAPI_CPP_EXCEPTIONS
953+
931954
#if NAPI_VERSION >= 8
932955
/// This operation can fail in case of Proxy.[[GetPrototypeOf]] calling into
933956
/// JavaScript.
@@ -976,6 +999,54 @@ namespace Napi {
976999
uint32_t Length() const;
9771000
};
9781001

1002+
#ifdef NAPI_CPP_EXCEPTIONS
1003+
class Object::const_iterator {
1004+
private:
1005+
enum class Type { BEGIN, END };
1006+
1007+
inline const_iterator(const Object* object, const Type type);
1008+
1009+
public:
1010+
inline const_iterator& operator++();
1011+
1012+
inline bool operator==(const const_iterator& other) const;
1013+
1014+
inline bool operator!=(const const_iterator& other) const;
1015+
1016+
inline std::pair<Value, Object::PropertyLValue<Value>> operator*() const;
1017+
1018+
private:
1019+
const Napi::Object* _object;
1020+
Array _keys;
1021+
uint32_t _index;
1022+
1023+
friend class Object;
1024+
};
1025+
1026+
class Object::iterator {
1027+
private:
1028+
enum class Type { BEGIN, END };
1029+
1030+
inline iterator(Object* object, const Type type);
1031+
1032+
public:
1033+
inline iterator& operator++();
1034+
1035+
inline bool operator==(const iterator& other) const;
1036+
1037+
inline bool operator!=(const iterator& other) const;
1038+
1039+
inline std::pair<Value, Object::PropertyLValue<Value>> operator*();
1040+
1041+
private:
1042+
Napi::Object* _object;
1043+
Array _keys;
1044+
uint32_t _index;
1045+
1046+
friend class Object;
1047+
};
1048+
#endif // NAPI_CPP_EXCEPTIONS
1049+
9791050
/// A JavaScript array buffer value.
9801051
class ArrayBuffer : public Object {
9811052
public:

test/object/object.cc

+16
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,19 @@ Value CreateObjectUsingMagic(const CallbackInfo& info) {
253253
return obj;
254254
}
255255

256+
#ifdef NAPI_CPP_EXCEPTIONS
257+
Value Sum(const CallbackInfo& info) {
258+
Object object = info[0].As<Object>();
259+
int64_t sum = 0;
260+
261+
for (const auto& e : object) {
262+
sum += static_cast<Value>(e.second).As<Number>().Int64Value();
263+
}
264+
265+
return Number::New(info.Env(), sum);
266+
}
267+
#endif // NAPI_CPP_EXCEPTIONS
268+
256269
Value InstanceOf(const CallbackInfo& info) {
257270
Object obj = info[0].As<Object>();
258271
Function constructor = info[1].As<Function>();
@@ -299,6 +312,9 @@ Object InitObject(Env env) {
299312
exports["hasPropertyWithCppStyleString"] = Function::New(env, HasPropertyWithCppStyleString);
300313

301314
exports["createObjectUsingMagic"] = Function::New(env, CreateObjectUsingMagic);
315+
#ifdef NAPI_CPP_EXCEPTIONS
316+
exports["sum"] = Function::New(env, Sum);
317+
#endif // NAPI_CPP_EXCEPTIONS
302318

303319
exports["addFinalizer"] = Function::New(env, AddFinalizer);
304320
exports["addFinalizerWithHint"] = Function::New(env, AddFinalizerWithHint);

test/object/object.js

+42
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,46 @@ function test(binding) {
156156
assert.strictEqual(binding.object.instanceOf({}, Ctor), false);
157157
assert.strictEqual(binding.object.instanceOf(null, Ctor), false);
158158
}
159+
160+
if ('sum' in binding.object) {
161+
{
162+
const obj = {
163+
'-forbid': -0x4B1D,
164+
'-feedcode': -0xFEEDC0DE,
165+
'+office': +0x0FF1CE,
166+
'+forbid': +0x4B1D,
167+
'+deadbeef': +0xDEADBEEF,
168+
'+feedcode': +0xFEEDC0DE,
169+
};
170+
171+
let sum = 0;
172+
for (const key in obj) {
173+
sum += obj[key];
174+
}
175+
176+
assert.strictEqual(binding.object.sum(obj), sum);
177+
}
178+
179+
{
180+
const obj = new Proxy({
181+
'-forbid': -0x4B1D,
182+
'-feedcode': -0xFEEDC0DE,
183+
'+office': +0x0FF1CE,
184+
'+forbid': +0x4B1D,
185+
'+deadbeef': +0xDEADBEEF,
186+
'+feedcode': +0xFEEDC0DE,
187+
}, {
188+
getOwnPropertyDescriptor(target, p) {
189+
throw new Error("getOwnPropertyDescriptor error");
190+
},
191+
ownKeys(target) {
192+
throw new Error("ownKeys error");
193+
},
194+
});
195+
196+
assert.throws(() => {
197+
binding.object.sum(obj);
198+
}, /ownKeys error/);
199+
}
200+
}
159201
}

0 commit comments

Comments
 (0)