Last active
May 25, 2025 07:41
-
-
Save vurtun/192cac1f1818417d7b4067d60e4fe921 to your computer and use it in GitHub Desktop.
Revisions
-
vurtun renamed this gist
Oct 26, 2020 . 1 changed file with 0 additions and 0 deletions.There are no files selected for viewing
File renamed without changes. -
vurtun revised this gist
Oct 26, 2020 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ API Design: Coroutines APIs (Janurary-2017) ----------------------------- I am currently dealing with a lot of libraries at work. Both third party as well as libraries written or being currently in process of being -
vurtun revised this gist
Jun 3, 2018 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -310,6 +310,6 @@ otherwise well written library just because abstractions are to hastely applied and granularity is not taken into account. Any kind of feedback is welcome and if there is some interest I may write a few more of these on API design. [1] https://wiki.qt.io/API_Design_Principles [2] https://www.youtube.com/watch?v=ZQ5_u8Lgvyk (Casey Muratori - Designing and Evaluating Reusable Components - 2004) [3] https://gist.github.com/pervognsen/d57cdc165e79a21637fe5a721375afba (alternative API - Per Vognsen) -
vurtun revised this gist
Jun 3, 2018 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -210,7 +210,7 @@ while (unzip(&un, &req, 0, 0, 0, 0);) { un.toc.addr = malloc(req.toc.size); un.toc.alignment = req.toc.alignment; un.toc.size = req.toc.size; } break;} } assert(!un.err); ``` -
vurtun revised this gist
Jun 3, 2018 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -58,23 +58,23 @@ easy to do and hard things possible'. In general the two main characteristics of APIs are control and ease of use: For orthogonal APIs you preferably want: 1. Unabstracted control over resources for library user: By Unabstracted I mean does not rely on abstraction to provide resources (templates, allocators, file abstractions,callbacks,...). Instead resources are either provided beforehand or can only be requested, but never taken. 2. Simple but not neccessaringly easy to use Simple and easy are probabily one of the most misused words. Simple is an absolute term of how intertwined your design is and easy as an relative term of how much work it takes to get things running with your library. While for diagonal APIs it is more preferable to have: 1. library controls resources Control over resources ranges from abstracted to completly taken away from library user. 2. Easy to use but not neccessaringly simple Main focus is in making things as easy as possible for new users. Basically make easy things easy to do. -
vurtun revised this gist
Jun 3, 2018 . 1 changed file with 39 additions and 37 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -62,7 +62,7 @@ For orthogonal APIs you preferably want: By Unabstracted I mean does not rely on abstraction to provide resources (templates, allocators, file abstractions,callbacks,...). Instead resources are either provided beforehand or can only be requested, but never taken. 2.) Simple but not neccessaringly easy to use Simple and easy are probabily one of the most misused words. Simple is an absolute term of how intertwined your @@ -73,7 +73,7 @@ For orthogonal APIs you preferably want: 1.) library controls resources Control over resources ranges from abstracted to completly taken away from library user. 2.) Easy to use but not neccessaringly simple Main focus is in making things as easy as possible for new users. Basically make @@ -102,12 +102,12 @@ floating around but in general most provide an API roughly like this (does not matter if OO or imperative): ```c struct unzip {...}; int unzip_open(struct unzip*, const char *path); int unzip_list(struct unzip*, struct unzip_file_info *array_to_fill); int unzip_stat(struct unzip*, const char *file, struct unzip_file_info *info); int unzip_extract(struct unzip*, const char *file, void *mem, size_t size); int unzip_close(struct unzip*); ``` I hope most of these functions are self-explanatory. You have a function @@ -241,9 +241,11 @@ to transistion between. Another example are most text file formats like JSON or XML. Most library APIs for these two formats look generally similar to this: ```c int json_load(struct json*, const char *path); int json_load_string(struct json*, const char *str); struct json_value *json_query(struct json*, const char *path); ``` Once again this is a good, easy to understand and use API. Like with the previous example you could provide additional abstraction. Abstract files and memory management. @@ -261,39 +263,39 @@ diagonal API for ease of use. Rarely you get a orthogonal API as well. Enough talk lets look on what I would propose for a orthogonal API: ```c enum json_token_type; struct json_token { enum json_token_type type; const char *str; size_t size; }; struct json { const char *stream; size_t available; }; int json_read(struct json*, struct json_token*); ``` This is a simple streaming API which just reads in one token after the other and does not care for memory or file resources as long as it has a stream of text to process. A simple use case example would be: ```c void *file_memory = ...; size_t file_size = ...; struct json js; js.stream = file_memory; js.available = file_size; struct json_token tok; while (json_read(&js, &tok)) { if (tok.type == JSON_OBJECT_BEGIN) { /* ... */ } else if (tok.type == JSON_OBJECT_END) { /* ... */ } else if (...) } ``` Once again this orthogonal API is not as easy to use as a simple call to -
vurtun revised this gist
Jun 3, 2018 . 1 changed file with 64 additions and 70 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -59,14 +59,11 @@ In general the two main characteristics of APIs are control and ease of use: For orthogonal APIs you preferably want: 1) Unabstracted control over resources for library user: By Unabstracted I mean does not rely on abstraction to provide resources (templates, allocators, file abstractions,callbacks,...). Instead resources are either provided beforehand or can only be requested, but never taken. 2.) Simple but not neccessaringly easy to use Simple and easy are probabily one of the most misused words. Simple is an absolute term of how intertwined your design is and easy as an relative term of how much work @@ -75,12 +72,9 @@ For orthogonal APIs you preferably want: While for diagonal APIs it is more preferable to have: 1.) library controls resources Control over resources ranges from abstracted to completly taken away from library user. 2.) Easy to use but not neccessaringly simple Main focus is in making things as easy as possible for new users. Basically make easy things easy to do. @@ -138,46 +132,46 @@ Once again this orthogonal API is not meant to replace the diagonal API. Instead provides the basis or foundation to implement it. So enough talk here is my low-level API: ```c union unzip_request { int type; struct file { int type; size_t offset; size_t available; } file; struct toc { int type; size_t size; size_t alignment; } toc; struct memory { int type; size_t size; } mem; }; struct unzip { enum unzip_status err; struct file { void *mapped; size_t offset; size_t available; size_t total_size; } file; struct toc { void *addr; size_t alignment; size_t size; } toc; struct memory { void *addr; size_t size; } mem; }; int unzip_init(struct unzip*, size_t total_size); int unzip_init_with_toc(struct unzip*, void *toc, size_t size); int unzip(struct unzip*, union unzip_request*, int file_index, void **mem, size_t *size, struct unzip_file_info *info); ``` First things first. This API is obviously a lot harder to understand than @@ -196,29 +190,29 @@ and provides either exactly what was previously requested or more. Finally you c So lets take a look how function 'unzip_open' could be implemented that way (another version here [3]): ```c struct unzip un; byte *zip_file_memory = ... size_t zip_file_size = ... union unzip_request req; unzip_init(&un, zip_file_size); while (unzip(&un, &req, 0, 0, 0, 0);) { switch (req.type) { case UNZIP_REQUEST_FILE_MAPPING: { /* request file mapping */ un.file.offset = req.file.offset; un.file.available = req.file.available; un.file.mapped = zip_file_memory + req.file.offset; } break; case UNZIP_REQUEST_TOC_MEMORY: { /* request memory for table of contents */ free(un.toc.addr); un.toc.addr = malloc(req.toc.size); un.toc.alignment = req.toc.alignment; un.toc.size = req.toc.size; } break; } assert(!un.err); ``` This is a lot of code on the library user side. But like I said low-level or -
vurtun renamed this gist
Jun 3, 2018 . 1 changed file with 15 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -107,12 +107,14 @@ First up is a zip archive unpack API. There are lots of them floating around but in general most provide an API roughly like this (does not matter if OO or imperative): ```c struct unzip {...}; int unzip_open(struct unzip*, const char *path); int unzip_list(struct unzip*, struct unzip_file_info *array_to_fill); int unzip_stat(struct unzip*, const char *file, struct unzip_file_info *info); int unzip_extract(struct unzip*, const char *file, void *mem, size_t size); int unzip_close(struct unzip*); ``` I hope most of these functions are self-explanatory. You have a function to open and close a zip file. Functions to query file information and @@ -135,6 +137,7 @@ But it does not have to be that way. Next up is my interpretation of a orthogona Once again this orthogonal API is not meant to replace the diagonal API. Instead it provides the basis or foundation to implement it. So enough talk here is my low-level API: ```c union unzip_request { int type; struct file { @@ -175,6 +178,7 @@ provides the basis or foundation to implement it. So enough talk here is my low- int unzip_init(struct unzip*, size_t total_size); int unzip_init_with_toc(struct unzip*, void *toc, size_t size); int unzip(struct unzip*, union unzip_request*, int file_index, void **mem, size_t *size, struct unzip_file_info *info); ``` First things first. This API is obviously a lot harder to understand than the first API. While it has fewer functions it has a more complex data @@ -191,27 +195,31 @@ and provides either exactly what was previously requested or more. Finally you c So lets take a look how function 'unzip_open' could be implemented that way (another version here [3]): ```c struct unzip un; byte *zip_file_memory = ... size_t zip_file_size = ... union unzip_request req; unzip_init(&un, zip_file_size); while (unzip(&un, &req, 0, 0, 0, 0);) { switch (req.type) { case UNZIP_REQUEST_FILE_MAPPING: { /* request file mapping */ un.file.offset = req.file.offset; un.file.available = req.file.available; un.file.mapped = zip_file_memory + req.file.offset; } break; case UNZIP_REQUEST_TOC_MEMORY: { /* request memory for table of contents */ free(un.toc.addr); un.toc.addr = malloc(req.toc.size); un.toc.alignment = req.toc.alignment; un.toc.size = req.toc.size; } break; } assert(!un.err); ``` This is a lot of code on the library user side. But like I said low-level or orthogonal code is simpler but not necessarily easier. But the user has total @@ -258,6 +266,7 @@ diagonal API for ease of use. Rarely you get a orthogonal API as well. Enough talk lets look on what I would propose for a orthogonal API: ```c enum json_token_type; struct json_token { enum json_token_type type; @@ -269,11 +278,13 @@ Enough talk lets look on what I would propose for a orthogonal API: size_t available; }; int json_read(struct json*, struct json_token*); ``` This is a simple streaming API which just reads in one token after the other and does not care for memory or file resources as long as it has a stream of text to process. A simple use case example would be: ```c void *file_memory = ...; size_t file_size = ...; @@ -289,6 +300,7 @@ text to process. A simple use case example would be: /* ... */ } else if (...) } ``` Once again this orthogonal API is not as easy to use as a simple call to 'json_load'. But it provides a lot more control and allows for different -
vurtun revised this gist
Jun 18, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -1,4 +1,4 @@ API Design: Granularity (Janurary-2017) ----------------------------- I am currently dealing with a lot of libraries at work. Both third party as well as libraries written or being currently in process of being -
vurtun revised this gist
Feb 21, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -215,7 +215,7 @@ So lets take a look how function 'unzip_open' could be implemented that way (ano This is a lot of code on the library user side. But like I said low-level or orthogonal code is simpler but not necessarily easier. But the user has total control over all resources. In this case both memory as well as file resources. The library only knows about memory and it does not care where it came from. Which in term is a simpler design but not necessarily easier to use. -
vurtun revised this gist
Feb 21, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -83,7 +83,7 @@ For orthogonal APIs you preferably want: ----------------------------------------- Main focus is in making things as easy as possible for new users. Basically make easy things easy to do. Important to note here. What I just described is not absolute. Instead it depends heavily on the problem you are solving. So -
vurtun revised this gist
Feb 9, 2017 . 1 changed file with 10 additions and 10 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -62,8 +62,8 @@ For orthogonal APIs you preferably want: ---------------------------------------------------- By Unabstracted I mean does not rely on abstraction to provide resources (templates, allocators, file abstractions,callbacks,...). Instead resources are either provided beforehand or can only be requested, but never taken. 2.) Simple but not neccessaringly easy to use ------------------------------------------- @@ -81,13 +81,13 @@ For orthogonal APIs you preferably want: 2.) Easy to use but not neccessaringly simple ----------------------------------------- Main focus is in making things as easy as possible for new users. Basically make easy things need to be easy to do. Important to note here. What I just described is not absolute. Instead it depends heavily on the problem you are solving. So it is more like a pointer with some compromises to be taken. Furthermore neither orthogonal or diagonal APIs are "bad" or "good" in any sense of the imagination. They just have different use cases and goals. @@ -115,8 +115,8 @@ like this (does not matter if OO or imperative): int unzip_close(struct unzip*); I hope most of these functions are self-explanatory. You have a function to open and close a zip file. Functions to query file information and to extract a file. You could also add some more functionality like open from memory and extracting a file to an OS path and other extracting variants. You furthermore could provide abstractions for file input and memory management and error handling. But I want to keep it simple for now. @@ -178,9 +178,9 @@ provides the basis or foundation to implement it. So enough talk here is my low- First things first. This API is obviously a lot harder to understand than the first API. While it has fewer functions it has a more complex data structure and function arguments. Let me try to explain it. Basically this is what I would describe as an request based API (also known as coroutine, state machine or push/pull APIs). You repeatedly call `unzip` and each time the API will return to you what is currently needed to process the zip archive. So if you call `unzip` the first time you would get an request back for file access. -
vurtun revised this gist
Feb 9, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -44,7 +44,7 @@ biggest issue I encountered so far in libraries. If there is any interest I may write a little bit more about each in a similar post. Granularity is at its core a simple concept. For every high-level API there needs to be a low-level API to achieve the same goal with more user control. Casey at this point talks about functions instead of APIs but I try to keep it more abstract. -
vurtun revised this gist
Feb 4, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -180,7 +180,7 @@ First things first. This API is obviously a lot harder to understand than the first API. While it has fewer functions it has a more complex data structure. Let me try to explain it. Basically this is what I would describe as an request based API (also known as coroutine, state machine or push/pull APIs). You repeatedly call `unzip` and each time the API will return to you what is currently needed to process the zip archive. So if you call `unzip` the first time you would get an request back for file access. -
vurtun revised this gist
Feb 4, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -116,8 +116,8 @@ like this (does not matter if OO or imperative): I hope most of these functions are self-explanatory. You have a function to open and close a zip file. Functions to query file information and finally functions to extract a file. You could add some more functionality like open from memory and extracting a file to an OS path and other extracting variants. You furthermore could provide abstractions for file input and memory management and error handling. But I want to keep it simple for now. -
vurtun revised this gist
Feb 4, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -116,7 +116,7 @@ like this (does not matter if OO or imperative): I hope most of these functions are self-explanatory. You have a function to open and close a zip file. Functions to query file information and finally functions to extract a file. You could add some more functionality like opening from memory and extracting a file to an OS path and other variants of extracting. You furthermore could provide abstractions for file input and memory management and error handling. But I want to keep it simple for now. -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 3 additions and 3 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -251,9 +251,9 @@ So what are the problems with this API. I don't always want to create a DOM. I o to directly parse the file. You could even go as far as we did by writing a parser generator which hand parses the file and fills our program specific data structures with data. This simply is not possible with the above API. I am now forced to rewrite the whole library because of API and therefore design decisions. Once again this is not that these diagonal APIs are bad in any way. But only providing one either orthogonal or diagional API is. Most of the time however what is written is only the diagonal API for ease of use. Rarely you get a orthogonal API as well. Enough talk lets look on what I would propose for a orthogonal API: -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -237,7 +237,7 @@ multiple. Each providing a tradeoff between control and ease of use, with an opt to transistion between. Another example are most text file formats like JSON or XML. Most library APIs for these two formats look generally similar to this: int json_load(struct json*, const char *path); int json_load_string(struct json*, const char *str); -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -114,7 +114,7 @@ like this (does not matter if OO or imperative): int unzip_extract(struct unzip*, const char *file, void *mem, size_t size); int unzip_close(struct unzip*); I hope most of these functions are self-explanatory. You have a function to open and close a zip file. Functions to query file information and finally functions to extract a file. You could add some more functions like opening from memory and extracting a file to an OS path and other variants of extracting. -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -251,10 +251,10 @@ So what are the problems with this API. I don't always want to create a DOM. I o to directly parse the file. You could even go as far as we did by writing a parser generator which hand parses the file and fills our program specific data structures with data. This simply is not possible with the above API. I am now forced to rewrite the whole library because of the API even if what I need is already exists. But it was not written to be exposed as an API. Once again this is not that these diagonal APIs are bad in any way. It just only supports a high-level way of use. Most of the time however what is written is only the diagonal API for ease of use. Rarely you get a orthogonal API as well. Enough talk lets look on what I would propose for a orthogonal API: -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -222,7 +222,7 @@ term is a simpler design but not necessarily easier to use. But what about multithreading. Well as soon as the above code run correctly the table of contents will be inside the 'toc' memory block. You can take this memory block and initialize another unzip struct by calling 'unzip_init_with_toc' and load files in parallel. Furthermore you can even store the toc to disk or send it over sockets. You could even directly store it in a file and load it at runtime and just access everything in a multithreaded fashion from the beginning. -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -171,6 +171,7 @@ provides the basis or foundation to implement it. So enough talk here is my low- size_t size; } mem; }; int unzip_init(struct unzip*, size_t total_size); int unzip_init_with_toc(struct unzip*, void *toc, size_t size); int unzip(struct unzip*, union unzip_request*, int file_index, void **mem, size_t *size, struct unzip_file_info *info); -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 0 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -152,6 +152,7 @@ provides the basis or foundation to implement it. So enough talk here is my low- size_t size; } mem; }; struct unzip { enum unzip_status err; struct file { -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 8 additions and 9 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -181,9 +181,9 @@ an request based API (also known as coroutine, state machine or push/pull APIs). You repeatatly call `unzip` and each time the API will return to you what is currently needed to process the zip archive. So if you call `unzip` the first time you would get an request back for file access. So struct `request` would contain a file offset and the number of bytes to be mapped written in 'request.file'. The user fills out 'unzip.file' and provides either exactly what was previously requested or more. Finally you call function `unzip` again. @@ -215,7 +215,7 @@ This is a lot of code on the library user side. But like I said low-level or orthogonal code is simpler but not necessarily easier. But the user has total control over all resource. In this case both memory as well as file resources. The library only knows about memory and it does not care where it came from. Which in term is a simpler design but not necessarily easier to use. But what about multithreading. Well as soon as the above code run correctly the table of contents will be inside the 'toc' memory block. You can take this @@ -250,10 +250,9 @@ to directly parse the file. You could even go as far as we did by writing a pars generator which hand parses the file and fills our program specific data structures with data. This simply is not possible with the above API. I am now forced to rewrite the whole API even if what I need is actually already inside the library. But it was not written to be exposed as an API. Once again this is not that this API is bad in any way. It just only supports a high-level way to use. Most of the time however what is written is only the diagonal API for ease of use. Enough talk lets look on what I would propose for a orthogonal API: @@ -292,7 +291,7 @@ text to process. A simple use case example would be: Once again this orthogonal API is not as easy to use as a simple call to 'json_load'. But it provides a lot more control and allows for different use cases while it also can be used to actually implement the diagonal API from above. To sum this all up I hope I could provide a small overview over granularity, diagonality and orthogonality in API design. Nothing I proposed here invalidates -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 4 additions and 4 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -136,19 +136,19 @@ Once again this orthogonal API is not meant to replace the diagonal API. Instead provides the basis or foundation to implement it. So enough talk here is my low-level API: union unzip_request { int type; struct file { int type; size_t offset; size_t available; } file; struct toc { int type; size_t size; size_t alignment; } toc; struct memory { int type; size_t size; } mem; }; -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -132,8 +132,8 @@ Another questions especially important today is multithreading. Does this library support multithreading and how easy is it to implement. So most of these problems are more advanced and often require a complete rewrite of a library. But it does not have to be that way. Next up is my interpretation of a orthogonal API. Once again this orthogonal API is not meant to replace the diagonal API. Instead it provides the basis or foundation to implement it. So enough talk here is my low-level API: union unzip_request { int code; -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -131,8 +131,8 @@ away from the user of this API. Both file handling and memory management. Another questions especially important today is multithreading. Does this library support multithreading and how easy is it to implement. So most of these problems are more advanced and often require a complete rewrite of a library. But it does not have to be that way. Next up is my interpretation of a orthogonal API. Once again this API does not replace the other API. Instead it provides the basis or foundation to implement it. So enough talk here is my low-level API: union unzip_request { -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 6 additions and 6 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -121,12 +121,12 @@ from memory and extracting a file to an OS path and other variants of extracting You furthermore could provide abstractions for file input and memory management and error handling. But I want to keep it simple for now. I would proclaim that this is a good API. I bet that every somewhat proficent programmer could understand and use this just fine. So what is the problem here? I mean there must be a reason why I took this example. For me this is a high-level or diagonal API. It at least fits the description I gave at the top of this post. First of resource control is completly taken or abstracted away from the user of this API. Both file handling and memory management. Another questions especially important today is multithreading. Does this library support multithreading and how easy is it to implement. So most of these @@ -245,7 +245,7 @@ Once again this is a good, easy to understand and use API. Like with the previou example you could provide additional abstraction. Abstract files and memory management. Good error handling. Finally few more utility and "redundant" functions. So what are the problems with this API. I don't always want to create a DOM. I often just want to directly parse the file. You could even go as far as we did by writing a parser generator which hand parses the file and fills our program specific data structures with data. This simply is not possible with the above API. I am now forced to rewrite -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -61,7 +61,7 @@ For orthogonal APIs you preferably want: 1) Unabstracted control over resources for library user: ---------------------------------------------------- By Unabstracted I mean does not rely on abstraction to provide resources (templates, allocators, file abstractions,callbacks,...). Instead resources are either provided or can only be requested and not taken. -
vurtun revised this gist
Feb 2, 2017 . 1 changed file with 2 additions and 2 deletions.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -196,12 +196,12 @@ So lets take a look how function 'unzip_open' could be implemented that way (ano union unzip_request req; unzip_init(&un, zip_file_size); while (unzip(&un, &req, 0, 0, 0, 0);) { if (req.type == UNZIP_REQUEST_FILE_MAPPING) { /* request file mapping */ un.file.offset = req.file.offset; un.file.available = req.file.available; un.file.mapped = zip_file_memory + req.file.offset; } else if (req.type == UNZIP_REQUEST_TOC_MEMORY) { /* request memory for table of contents */ free(un.toc.addr); un.toc.addr = malloc(req.toc.size);
NewerOlder