0% found this document useful (0 votes)
60 views57 pages

CC 04 Maps

Uploaded by

Ajay Singh Negi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
60 views57 pages

CC 04 Maps

Uploaded by

Ajay Singh Negi
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 57

Building a Better

Object
Dr. Charles R. Severance
www.cc4e.com
code.cc4e.com (sample code)
online.dr-chuck.com
Problems with our "pydict" class
• The previous dict implementation was just a linked list with a key – we
need to build multiple implementations for different performance
requirements
• We need to include our methods in the struct instead of using prefix-
style function naming conventions
• We need a better abstraction for looping that does not require
"peeking" at the class-internal attributes
Object Oriented Principles
• Encapsulation – Bundling code and data together
• https://en.wikipedia.org/wiki/Encapsulation_(computer_programming)
• Abstraction – Separate interface from implementation
• https://en.wikipedia.org/wiki/Abstraction_(computer_science)
• Inheritance – Creating new classes by extending existing classes (DRY)
• https://en.wikipedia.org/wiki/Inheritance_(object-oriented_programming)
• Polymorphism - Later 
• https://en.wikipedia.org/wiki/Polymorphism_(computer_science)
Encapsulation by Naming
Convention
• So far to keep things simple we associate a method for a class with a
simple naming convention
• It seems simple enough but is a bad idea in practice.
• Python strings are objects that follow the principle of encapsulation
• PHP strings are a type plus an associated / prefixed library

• Before I show you the next slide, I need to emphasize that I love many
many things about PHP – but there are some annoyances 
Encapsulation by Naming
Convention (is bad)
# Python # PHP
x = "A string with old in it" $x = "A string with old in it";

print(x.find('with')) print(strpos($x,'with')."\n");

y = x.replace('old', 'new') $y = str_replace(???, ???, ???);

print(y) print($y."\n");

print(len(y)) print(???????($y)."\n");
Encapsulation by Naming
Convention (is bad)
# Python # PHP
x = "A string with old in it" $x = "A string with old in it";

print(x.find('with')) print(strpos($x,'with')."\n");

y = x.replace('old', 'new') $y = str_replace('old', 'new', $x);

print(y) print($y."\n");

print(len(y)) print(strlen($y)."\n");
Putting Methods in the Structure
int main(void) int main(void)
{ {
struct pydict * dct = pydict_new(); struct pydict * dct = pydict_new();

pydict_put(dct, "z", "Catch phrase"); dct->put(dct, "z", "Catch phrase");


pydict_put(dct, "z", "W"); dct->put(dct, "z", "W");

printf("Length =%d\n",pydict_len(dct)); printf("Length =%d\n",dct->len(dct));

printf("z=%s\n", pydict_get(dct, "z")); printf("z=%s\n", dct->get(dct, "z"));

pydict_del(dct); dct->del(dct);
} }

Because we are emulating OO patterns in C, moving new() into the structure is possible but adds a layer of
complexity at compile and run time. Similarly we need to have 'dct' twice in method calls so methods have
access to the instance in the methods. Languages like C++ and Python solve this by adjusting their compiler.
Access Control / "Leaky"
Abstractions
• When the class is designed such that the calling code needs to look at
data attributes *inside* the class – we call this a "leaky abstraction"
• The implementation details like the choice of an internal variable
name within the class are "leaking" out into the calling code.
• When calling code depends on this internal implementation names
and approaches, it means that we cannot change the code in the class
without breaking calling code
• We need to define a "contract" between the class and its calling code
that we agree won't change. We call this contract an "interface".
struct dnode {
char *key;
int main(void)
{ char *value;
struct pydict * dct = pydict_new(); struct dnode *next;
pydict_put(dct, "z", "Catch phrase"); };
pydict_print(dct);
pydict_put(dct, "z", "W");
pydict_print(dct); struct pydict {
pydict_put(dct, "y", "B"); struct dnode *head;
pydict_put(dct, "c", "C"); struct dnode *tail;
pydict_put(dct, "a", "D");
pydict_print(dct); int count;
printf("Length =%d\n",pydict_len(dct)); };
printf("z=%s\n", pydict_get(dct, "z"));
printf("x=%s\n", pydict_get(dct, "x"));

printf("\nDump\n");

for(struct dnode * cur = dct->head; cur != NULL ; cur = cur->next ) {


printf("%s=%s\n", cur->key, cur->value);
}

pydict_del(dct);
}
cc_03_04.c
Controlling Access to Object
Attributes
• As we build a class, we decide which elements are part of our
contract with our calling code
• In real OO languages, in the class definition, we mark attributes and
methods with our intended access level
• Accessible by the calling code – "public"
• Accessible only within the class – "private"
• Accessible within the class and other *internal* classes – "protected"
struct dnode {
/* protected */ char *key;
int main(void) /* protected */ char *value;
{ /* protected */ struct dnode *next;
struct pydict * dct = pydict_new(); };
pydict_put(dct, "z", "Catch phrase");
pydict_print(dct); struct pydict {
pydict_put(dct, "z", "W"); /* private */ struct dnode *head;
pydict_print(dct); /* private */ struct dnode *tail;
pydict_put(dct, "y", "B"); /* private */ int count;
pydict_put(dct, "c", "C");
pydict_put(dct, "a", "D"); /* public */ pydict_len();
pydict_print(dct); /* public */ pydict_len();
printf("Length =%d\n",pydict_len(dct)); /* public */ pydict_get();
/* public */ pydict_del();
printf("z=%s\n", pydict_get(dct, "z"));
printf("x=%s\n", pydict_get(dct, "x")); }; Abstraction Boundary
printf("\nDump\n");

for(struct dnode * cur = dct->head; cur != NULL ; cur = cur->next ) {


printf("%s=%s\n", cur->key, cur->value);
}
Early C++ access control syntax was
pydict_del(dct);
}
implemented by a pre-processor.

cc_03_04.c
Access Control in Java
public class Point {
private double x,y;

Point(double x, double y) {
this.x = x;
this.y = y;
}

public void dump() {


System.out.printf("%s x=%f y=%f\n", this, this.x, this.y);
}
}
Access Control in C++
class Point {
private:
double x, y;

public:
Point(double xc, double yc) {
x = xc;
y = yc;
};

void dump() {
printf("Object point x=%f y=%f\n", x, y);
}
};
Access Control in Python
class Point:
__x = 0.0
__y = 0.0

def __init__(self, x, y):


self.__x = x
self.__y = y

def dump(self):
print('Object point@%x x=%f y=%f' % (id(self),self.__x,self.__y))
What in a Map?
For dictionary like structures
Modern Maps – Key / Value Pairs
• "Map" is a common term we use to describe abstract key/value
collections
• C++ map
• Python dictionary
• Java Map
• PHP Arrays
• Iterator Pattern as an abstraction for looping across multiple
implementations
d = dict()

print("Testing dict class\n");


d["z"] = 8 Testing dict class
d["z"] = 1
d["y"] = 9 {'z': 1, 'y': 9, 'b': 3, 'a': 4}
d["b"] = 3 z=1
d["a"] = 4 x=42
print(d); <class 'dict_itemiterator'>
('z', 1)
print("z=%d" % (d.get("z", 42), )); ('y', 9)
print("x=%d" % (d.get("x", 42), )); ('b', 3)
('a', 4)
items = iter(d.items())
print(type(items));

entry = next(items, False)


while (entry) :
print(entry)
entry = next(items, False) cc_04_03.py
$a = array();
Testing dict class
print("Testing php arrays\n"); Array
(
$a["z"] = 8;
[z] => 1
$a["z"] = 1; [y] => 9
$a["y"] = 9; [b] => 3
$a["b"] = 3; [a] => 4
$a["a"] = 4; )
print_r($a); z=1
x=42
printf("z=%d\n", $a["z"] ?? 42);
printf("x=%d\n", $a["x"] ?? 42); Iterate
z=1
y=9
printf("\nIterate\n"); b=3
foreach( $a as $k => $v ) { a=4
printf(" %s=%d\n", $k, $v);
}

cc_04_03.php
C++

https://cplusplus.com/reference/map/map/
#include <iostream>
#include <map>
using namespace std; Testing map class
z=1
int main() { x=42
map<string, int> mp;
Iterate
printf("Testing map class\n");
a=4
mp["z"] = 8;
mp["z"] = 1;
b=3
mp["y"] = 2; y=2
mp["b"] = 3; z=1
mp["a"] = 4;

printf("z=%d\n", (mp.count("z") ? mp["z"] : 42));


printf("x=%d\n", (mp.count("x") ? mp["x"] : 42));

printf("\nIterate\n");
for (auto cur = mp.begin(); cur != mp.end(); ++cur) {
printf(" %s=%d\n", cur->first.c_str(), cur->second);
}
}
cc_04_03.cpp
Java Map<String, Integer>

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html
import java.util.Map;
import java.util.TreeMap; Testing Map class
{a=4, b=3, y=2, z=1}
public class cc_04_03 { z=1
x=42
public static void main(String[] args)
{
Map<String, Integer> map = new TreeMap<String, Integer> (); Iterate
Key = a, Value = 4
System.out.printf("Testing Map class\n"); Key = b, Value = 3
map.put("z", 8); Key = y, Value = 2
map.put("z", 1); Key = z, Value = 1
map.put("y", 2);
map.put("b", 3);
map.put("a", 4);
System.out.println(map);

System.out.println("z="+map.getOrDefault("z", 42));
System.out.println("x="+map.getOrDefault("x", 42));

System.out.printf("\nIterate\n");
for (Map.Entry<String,Integer> entry : map.entrySet()) {
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
}

}
}
cc_04_03.java
d = dict()
Testing dict class
print("Testing dict class\n");
d["z"] = 8 {'z': 1, 'y': 9, 'b': 3, 'a': 4}
d["z"] = 1 z=1
d["y"] = 9 x=42
<class 'dict_itemiterator'>
d["b"] = 3
Iterate
d["a"] = 4 ('z', 1)
print(d); ('y', 9)
('b', 3)
print("z=%d" % (d.get("z", 42), )); ('a', 4)
print("x=%d" % (d.get("x", 42), ));

items = iter(d.items())
print(type(items));

print("Iterate");
entry = next(items, False)
while (entry) :
print(entry)
entry = next(items, False)

cc_04_03.py
A Minute of C++
Procedural

Hybrid

Object Oriented

Classes were
added to PHP in
ps://en.wikipedia.org/wiki/Object-oriented_programming 2000
// C++ 1980 – Pre-process + compile Three Syntaxes
map<string, int> mp;

mp["z"] = 8;

# Python 1991 - Interpreted


d = dict()

d["z"] = 8

// Java 1995 – Compiled


Map<String, Integer> map =
Java chose not to extend the language syntax to use
[] and instead used get() and put() methods. C++ has new TreeMap<String, Integer> ();
a "pretty unique" approach that makes the succinct /
natural syntax possible. The C++ syntax influenced map.put("z", 8);
the Python and most other syntaxes except for Java.
The C++ OO approach is somewhat
unique
#include <iostream>
• C++ allows a class class TenInt {
developer to create private:
int values[10];
classes that can be used public:

as if they new native int & operator [](const int & index) {
printf("– Returning reference to %d\n", index);
types like integer and }
return values[index];

floating point };

• Operator Overloading int main() {


TenInt ten;
ten[1] = 40;
printf("printf ten[1] contains %d\n", ten[1]);

ten[5] = ten[1] + 2;
printf("Done assigning ten[5]\n");
printf("printf ten[5] contains %d\n", ten[5]);
}

cc_04_04.cpp
#include <iostream>
-- Returning reference to 1
-- Returning reference to 1
class TenInt { printf ten[1] contains 40
private: -- Returning reference to 1
int values[10]; -- Returning reference to 5
public: Done assigning ten[5]
int & operator [](const int & index) { -- Returning reference to 5
printf("-- Returning reference to %d\n", index);
printf ten[5] contains 42
return values[index];
}
};

int main() {
TenInt ten; Java did not want to support call by
ten[1] = 40;
printf("printf ten[1] contains %d\n", ten[1]); reference, and even more did not
support returning a reference from
ten[5] = ten[1] + 2; within a function. C++ figured that a
printf("Done assigning ten[5]\n");
printf("printf ten[5] contains %d\n", ten[5]);
good programmer would use these
} features wisely.

cc_04_04.cpp
The C++ Influence in Python goes
very deep
• The Python approach to x = dict()
x[1] = 40
providing this syntax to us print('print x[1]', x.__getitem__(1))
was to extend the
language to transform the # x[5] = x[1] + 2
x.__setitem__(5, x.__getitem__(1) + 2)
bracket syntax into print(x)
function calls to internal
class methods

print x[1] 40
{1: 40, 5: 42}

cc_04_04.py
C

Python
C++

The open flow of


innovation and ideas
Python has operator class TenInt:
overloading! __values = dict()

def __setitem__(self, index, value) :


self.__values[index] = value
#include <iostream>
def __getitem__(self, index) :
class TenInt { return self.__values[index]
private:
int values[10]; ten = TenInt()
public: ten[1] = 40;
int & operator [](const int & index) { print("print ten[1] contains", ten[1]);
printf("-- Returning reference to %d\n", index);
return values[index]; ten[5] = ten[1] + 2;
} print("Done assigning ten[5]");
}; print("print ten[5] contains", ten[5]);

int main() {
TenInt ten;
ten[1] = 40;
printf("printf ten[1] contains %d\n", ten[1]);
print ten[1] contains 40
ten[5] = ten[1] + 2; Done assigning ten[5]
printf("Done assigning ten[5]\n");
printf("printf ten[5] contains %d\n", ten[5]); print ten[5] contains 42
}

cc_04_05.py
cc_04_04.cpp
Implementing
Encapsulation
Moving methods into our C-based Map class (refactor your existing code)
int main(void)
{
struct MapEntry *cur;
struct Map * map = Map_new();
Testing Map class
printf("Testing Map class\n"); Object Map count=4
map->put(map, "z", 8); z=1
map->put(map, "z", 1); y=2
map->put(map, "y", 2); b=3
map->put(map, "b", 3);
a=4
map->put(map, "a", 4);
map->dump(map);
z=1
x=42
printf("z=%d\n", map->get(map, "z", 42));
printf("x=%d\n", map->get(map, "x", 42));

/* No iterator (for now) */

map->del(map);
}
cc_04_03.c
MapEntry Structure
• This is the structure that
will make up the nodes
struct MapEntry {
in the list.
char *key; /* public */
• The key is a character int value; /* public */
string – the actual data struct MapEntry *__prev;
will be saved in a newly struct MapEntry *__next;
allocated space. };
• The value is an int and
will be allocated right in
the node.
Map structure struct Map {
/* Private attributes */
struct MapEntry *__head;
• This contains the struct MapEntry *__tail;
attributes and methods int __count;

• We will use pointers to /* Public methods */


functions to make it so void (*put)(struct Map* self,
we access the methods char *key, int value);
int (*get)(struct Map* self,
from the Map object. char *key, int def);
• Encapsulation is the int (*size)(struct Map* self);
bundling of attributes void (*dump)(struct Map* self);
void (*del)(struct Map* self);
and methods together };
Constructor
struct Map * Map_new() {
struct Map *p = malloc(sizeof(*p));
• Allocate the Map object
instance and fill it with p->__head = NULL;
defaults. p->__tail = NULL;
p->__count = 0;
• In a C++ class, the name of
Map_put() function is p->put = &__Map_put;
p->get = &__Map_get;
obscured and only p->size = &__Map_size;
accessible via the put() p->dump = &__Map_dump;
method p->del = &__Map_del;
return p;
}
Map_dump /**
* map->dump - In effect a toString() except we print
* the contents of the Map to stdout
*
* self – The pointer to the instance of this class.
• Build a simple debug */

tool right away  void __Map_dump(struct Map* self)


{
struct MapEntry *cur;
• We are *inside* the printf("Object Map count=%d\n", self->count);
for(cur = self->__head; cur != NULL ; cur = cur->__next ) {
class so accessing printf(" %s=%d\n", cur->key, cur->value);

private values is }
}

expected
Destructor
/**
* Destructor for the Map Class
• Free the allocated key *
* Loops through and frees all the keys and
strings, then the * entries in the map. The values are integers
MapEntry structure * so there is no need to free them.
*/
• Note that we take cur- void __Map_del(struct Map* self) {
struct MapEntry *cur, *next;
>next before we free the cur = self->__head;
while(cur) {
node, assuming that cur free(cur->key);
data might be gone. /* value is just part of the struct */
next = cur->__next;
• At the very end we free free(cur);
cur = next;
the Map structure }
free((void *)self);
}
/**

Map_get
* map->get - Locate and return the value for the
* corresponding key or a default value
*
* self - The pointer to the instance of this class.
* key - A character pointer to the key value
* def - A default value to return if the key is
• Returns the value stored * not in the Map

at the key or a default *


* Returns an integer
value *
* Sample call:
*
• Pretty simple when you * int ret = map->get(map, "z", 42);

can use __Map_find() *


* This method takes inspiration from the Python code:
*
* value = map.get("key", 42)
*/
int __Map_get(struct Map* self, char *key, int def)
{
struct MapEntry *retval = __Map_find(self, key);
if ( retval == NULL ) return def;
return retval->value;
}
Map_put /**
* map->put - Add or update an entry in the Map
*
* self - The pointer to the instance of this class.
• This is not used by * key - A character pointer to the key value
* value - The value to be stored with the associated key
main() – it is just for in- *

class use – that is the * If the key is not in the Map, an entry is added. If there
* is already an entry in the Map for the key, the value
definition of "private" in * is updated.
*
OO-speak * Sample call:
*
• Uses __Map_find() to *
*
map->put(map, "x", 42);

check if the key is * This method takes inspiration from the Python code:
*
already in the map *
*/
map["key"] = value

void __Map_put(struct Map* self, char *key, int value) {


...
}
Iterators
Looping while respecting the abstraction
boundary

Photo: https://www.flickr.com/photos/littledebbie11/4151828376/ - CC BY 2.0


int main(void)
{
struct Map * map = Map_new(); Testing Map class
struct MapEntry *cur;
Object Map count=4
struct MapIter *iter;
z=1
printf("Map test\n"); y=2
map->put(map, "z", 8); b=3
map->put(map, "z", 1);
map->put(map, "y", 2);
a=4
map->put(map, "b", 3); z=1
map->put(map, "a", 4); x=42
map->dump(map);

printf("z=%d\n", map->get(map, "z", 42)); Iterate


printf("x=%d\n", map->get(map, "x", 42)); y=2
b=3
printf("\nIterate\n");
iter = map->iter(map); a=4
while(1) {
cur = iter->next(iter);
if ( cur == NULL ) break;
printf("%s=%d\n", cur->key, cur->value);
}
iter->del(iter);

map->del(map); Recall that key and value are


} public attributes in MapEntry. cc_04_06.c
Simplifying our
head:
tail:

Pictures
key: z struct MapEntry {
value: 22 char *key; /* public */
int value; /* public */
prev: ∅ struct MapEntry *__prev;
struct MapEntry *__next;
next: };

struct Map {
struct MapEntry *__head;
struct MapEntry *__tail;
key: w ...
value: 42 };

prev:
next: head
z=22 w=42 ∅


Separation of Concerns
struct Map {
/* Attributes */

• Following the practice or "abstraction", struct MapEntry *__head;


struct MapEntry *__tail;

object builders make attributes critical int __count;

to the functioning of the object "private" /* Methods */


...

• We do not want our calling code to };

access head or count – and even worse /* This loop is OK in an object


the object will break badly if the main method – but not in main() */

program starts changing with these for (current = map->__head;


current != NULL;
values without full understanding of the current = current->__next )

implementation
{

https://en.wikipedia.org/wiki/Separation_of_concerns
About Iterators next x = {'a': 1, 'b': 2, 'c': 3}
print('x is', x)

y = list(x)
• To allow code outside the the print('y is', y)

object to traverse a list, we use it = iter(x)

iterators print('it is', it)

while True :
• Once we have an iterator, each item = next(it, False)
time we call "next" we get the if item is False : break
print('item is', item)
next item in the list until the end

x is {'a': 1, 'b': 2, 'c': 3}


y is ['a', 'b', 'c']
it is <dict_keyiterator object at 0x100410a40>
item is a https://en.wikipedia.org/wiki/Iterator
item is b
item is c
cc_05_06.py
Using an iterator printf("\nIterate\n");
iter = map->iter(map);
while(1) {
cur = iter->next(iter);
if ( cur == NULL ) break;
• You create the iterator }
printf(" %s=%d\n", cur->key, cur->value);

• Then in a loop, you call iter->del(iter);


cc_04_03.c
next() to get each
successive entry in the
map, until you exhaust
the entries
x = {'a': 1, 'b': 2, 'c': 3}
• We could make key and it = iter(x)
value private in MapEntry while True :

– but we just keep them item = next(it, False)


if item is False : break
public to reduce code size print('item is', item)

on slides cc_04_05.py
Struct MapIter
• The MapIter is a "related /*
* A MapIter contains the current item and whether
class" to it can access * this is a forward or reverse iterator.
*/
"protected" values in struct MapIter {
struct MapEntry *__current;
MapEntry without struct MapEntry* (*next)(struct MapIter* self);

violating the abstraction. };


void (*del)(struct MapIter* self);

current

head
b=14 d=21 f=19 ∅
Map_iter() /**
* __Map_iter - Create an iterator from the head the
* self - The pointer to the instance of this class.
*
* returns NULL when there are no entries in the Map
• We allocate a MapIter *
* This is inspired by the following Python code
and set it up with initial * that creates an iterator from a dictionary:
*
• If self->head is NULL, the *
*
x = {'a': 1, 'b': 2, 'c': 3}
it = iter(x)
list is empty. */
struct MapIter* __Map_iter(struct Map* self)

• We can access protected {


struct MapIter *iter = malloc(sizeof(*iter));
data in the Map class iter->__current = self->__head;
iter->next = &__MapIter_next;
because the MapIter iter->del = &__MapIter_del;
return iter;
implementation is part }

of the Map current


implementation
head
b=14 d=21 f=19 ∅
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅
Constructed, before the first call to next()
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅
Next is called, grab current, then advance
reval
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅
Next returns "b=14" and current is advanced
reval
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅

reval
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅

reval
MapIter_next() /**
* __MapIter_next - Advance the iterator forwards
* or backwards and return the next item
*
* self - The pointer to the instance of this class.
• Note we must return the *
* returns NULL when there are no more entries
current MapEntry *
* This is inspired by the following Python code:
before we advance *
* item = next(iterator, False)
current so we see the */

first MapEntry struct MapEntry* __MapIter_next(struct MapIter* self)


{
struct MapEntry * retval = self->__current;

if ( retval == NULL) return NULL;


self->__current = self->__current->__next;
return retval;
current }

head
b=14 d=21 f=19 ∅

reval
Using an iterator printf("\nIterate\n");
iter = map->iter(map);
while(1) {
• You create the iterator cur = iter->next(iter);
if ( cur == NULL ) break;
printf(" %s=%d\n", cur->key, cur->value);
• Then in a loop, you call }
next() to get each iter->del(iter);
cc_04_06.c
successive entry in the
map, until you exhaust
the entries
x = {'a': 1, 'b': 2, 'c': 3}
• We could make key and it = iter(x)
value private in MapEntry while True :

– but we just keep them item = next(it, False)


if item is False : break
public to reduce code size print('item is', item)

on slides cc_04_05.py
Summary
• We have improved the design of our class interface
• Abstraction
• Encapsulation

• We do this to allow multiple Map implementations of varying


complexity and improved performance characteristics
• Tree Structure
• Hash Structure
Acknowledgements / Contributions
These slides are Copyright 2023- Charles R. Severance (online.dr-chuck.com) Continue new Contributors and Translators here
as part of www.cc4e.com and made available under a Creative Commons
Attribution 4.0 License. Please maintain this last slide in all copies of the
document to comply with the attribution requirements of the license. If you
make a change, feel free to add your name and organization to the list of
contributors on this page as you republish the materials.

Initial Development: Charles Severance, University of Michigan School of


Information

Insert new Contributors and Translators here including names and dates

You might also like